輸入掩碼和UX表單
1)原則
1.幫忙,不要懲罰。掩碼引導輸入並減少錯誤,但不阻止打印和插入。
2.數據≠顯示。我們保留「原始」歸一化值,僅在UI中格式化。
3.可預測的光標。任何自動安裝都不會「跳躍」caret或打破undo/redo。
4.位置和設備。按區域和平臺劃分鍵盤、分隔符、日歷和貨幣。
5.可訪問性和隱私性。文本+圖標/顏色;敏感字段掩蓋但不幹擾密碼管理器/自動完成。
2)口罩何時合適(何時不合適)
使用:- 具有可持續結構的格式:電話,IBAN,PAN(地圖),CVC,日期,時間,索引,OTP。
- 帶分隔符的現金金額(打印時為「凈」輸入,藍調時為格式)。
- 代碼(裁判。編碼,促銷),固定長度。
- 名稱/地址/電子郵件(掩碼限制有效字符/語言)。
- 復雜的免費字段(評論,公司名稱)。
- 輸入格式可能未知(沒有國家/地區的國際編號)。
3)面具vs自動格式vs驗證
掩碼是「即時」結構的提示(括號,連字符);不得斷開輸入/插入。
自動格式-適用於藍色/焦點損失(數千個,IBAN空格)。
驗證是正確性邏輯(長度,校驗和和),在「blur」或「submit」之後顯示錯誤。
規則:掩碼不能取代驗證,自動格式不應改變輸入的含義。
4)鍵盤和HTML屬性
選擇正確的類型/模式以加快輸入速度並減少錯誤:5)Caret,copipast和正常化
不要打破caret:在自動插入字符(空格/括號)時,調整光標位置。
Copipast:插入時,清除空格/連字符→驗證→顯示格式。
正常化:trimming,替換字符的「曲線」(「O'→'0」不能!),翻譯成大寫的IBAN,統一日期格式的存儲(ISO)。
js const clean = s => s. replace(/[^\da-zA-Z]/g,'');
const normalizePAN = s => clean(s). slice (0.19) ;//no spaces/hyphens const normalizeIBAN = s => clean (s). toUpperCase(); // A–Z0–9
6)數字,貨幣和地方
輸入「如何打印」(公差「,」或「作為分隔符」),存儲在小單位(便士/美分)中。
在blure/sabmite後沿位置(數千人分組)顯示;聚焦顯示「原始」值,方便編輯。
明確指定貨幣並固定精度(例如,2個符號)。
js function parseMoney(input) {
//resolve both comma and period as decimal const s = input. replace(/\s/g,''). replace(',', '.');
const num = Number(s);
if (Number. isNaN(num)) return null;
return Math. round(num 100); // cents
}
function formatMoney(cents, locale='ru-RU', currency='RUB') {
return (cents/100). toLocaleString(locale, { style:'currency', currency });
}
7)日期和時間
如果本地采樣器在平臺上不舒服/不同-使用帶有「DD」面罩的文本框。MM.YYYY',但保留ISO 'YYYY-MM-DD'。
日期現實檢查(29.02,頻段),時間段在服務器上。
添加今天、現在、清除按鈕。
8)電話和國家
兩個字段:國家/地區(+代碼)和選定國家/地區的數字或「智能」面具。
插入完整的'+CC……'時,自動填充國家/地區。
存儲E.164('+CCXXXXXXXX),在本地顯示空格。
9)付款詳情: PAN/IBAN/CVC/EXP
PAN:4-4-4-4分組;含義僅為數字;Luhn-check;PAN沒有記錄/分析。
CVC:"password"樣式(隱藏),"autocomplete="cc-csc",不保存到草稿中。
EXP:「MM/YY」,2位數字後自動插入「/」,檢查範圍01-12和合理的一年。
IBAN:上例,僅在UI中存在空白;國家長度和校驗和檢查。
10)OTR/確認代碼
6(或N)具有自動對焦和自動轉換的單元格,從緩沖區插入可識別所有代碼。
"autocomplete="one-time-code",在移動上-從SMS中自動生成。
沒有拆分字段(一個字段)的備用輸入-用於屏幕閱讀器。
html
<div class="otp" role="group" aria-label="Код из SMS">
<input inputmode="numeric" maxlength="1">
<input inputmode="numeric" maxlength="1">
<!-- … -->
</div>
11)面具和a11 y
標簽是必需的('<label for>'),placeholder是示例而不是替換。
旁邊解釋規則:帶示例的幫助文本(「格式:+CC XXX-XX-XX」)。
通過"aria-describedby"鏈接錯誤,關鍵是"role="alert"。
文本和輪廓的對比≥ AA,「:focus-visible」不隱藏。
12)隱私和安全
敏感字段:不要拼寫、寫入RUM,不要保存到草稿中(PAN、CVC、護照)。
口罩和格式不必透露帳戶的有效性(「如果電子郵件已註冊……」-中性表述)。
關鍵軍刀的相容性和可追溯性(付款/費率)。
13)表格行為和性能
異步檢查(250-400毫秒),可見指示「我們檢查……」。
不要為了一個字段而阻擋整個屏幕;本地旋轉器/骨架。
Batchit DOM更改;僅為「轉換/操作性」動畫。
在移動上-當鍵盤出現時避免「跳躍」(安全區域,視覺運動元)。
14)代碼嗅覺
柔軟的手機面罩(無插入片段):js function formatPhoneVisible(value) {
const d = value. replace(/\D/g,''). slice(0,15);
if (!d) return '';
if (d. startsWith('7') d. startsWith('8')) {
return d. replace(/^([78])? (\d{3})(\d{3})(\d{2})(\d{2})./, '+7 ($2) $3-$4-$5');
}
// generic E.164 grouping: +CC XXX XXX XX XX return d. replace(/^(\d{1,3})(\d{0,3})(\d{0,3})(\d{0,2})(\d{0,2})./, (m,c1,c2,c3,c4,c5)=>
`+${c1}${c2?` ${c2}`:''}${c3?` ${c3}`:''}${c4?` ${c4}`:''}${c5?` ${c5}`:''}`.trim());
}
const input = document. querySelector('#phone');
input. addEventListener('input', e => {
const raw = e. target. value;
const pos = e. target. selectionStart;
const digitsBefore = raw. slice(0,pos). replace(/\D/g,''). length;
const cleaned = raw. replace(/[^\d+]/g,'');
const visible = formatPhoneVisible(cleaned);
e. target. value = visible;
// restore caret by counting digits let p = 0, count = 0;
while (p < e. target. value. length && count < digitsBefore) { if (/\d/.test(e. target. value[p])) count++; p++; }
e. target. setSelectionRange(p, p);
});
總和:「焦點原始→藍調格式」:
js const amount = document. getElementById('amount');
let cents = null;
amount. addEventListener('focus', () => {
if (cents!=null) amount. value = String(cents/100). replace('.', ',');
});
amount. addEventListener('blur', () => {
const v = parseMoney(amount. value) ;//from section 6 if (v = = null) return; cents = v;
amount. value = formatMoney(cents, 'ru-RU', 'RUB');
});
IBAN:上例和藍調分組:
js const iban = document. getElementById('iban');
iban. addEventListener('input', () => iban. value = iban. value. toUpperCase());
iban. addEventListener('blur', () => {
const raw = normalizeIBAN(iban. value);
iban. dataset. raw = raw ;//for iban submission. value = raw. replace(/(.{4})/g,'$1 '). trim () ;//view only
});
15)設計系統令牌(示例)
json
{
"input": {
"radius": 10,
"height": { "sm": 36, "md": 40, "lg": 48 },
"gap": 8,
"icon": 16
},
"mask": {
"debounceMs": 300,
"otpLength": 6,
"moneyPrecision": 2,
"phoneMaxDigits": 15
},
"a11y": {
"focusRing": { "width": 2, "offset": 2 },
"contrastAA": true
}
}
CSS預設:
css
.input { height:40px; padding:0 12px; border-radius:10px; }
.input:focus-visible { outline:2px solid var(--focus-ring); outline-offset:2px; }
.field-error { color: var(--role-danger); font-size:.875rem; margin-top:6px; }
.otp input { width:40px; text-align:center; }
16) iGaming的細節
付款/結論:PAN/IBAN/帶有軟口罩的 amount;嚴格的等速率,並且沒有敏感場的標記;關於傭金和時機的線索。
KYC:日期口罩,護照號碼(沒有「硬」過濾功能-考慮不同格式),文件大小/類型,預覽。
限制和負責任的遊戲:可理解的金額/時期(天/周/月),旁邊的輔助器,AAA對比。
投註:快速輸入總和(預設按鈕+字段),以「原始」數字為焦點,並按位置排列;「,「……./雙分隔符。
17)反模式
硬遮色片,禁止有效字符/插入。
自動格式的跳躍跑車;分配丟失/undo。
Placeholder代替標簽。
在值內自動添加貨幣(打破共計)。
「每個字符」錯誤,沒有刪除。
存儲中與本地相關的格式(存儲ISO/數字)。
編制PAN/護照號碼並顯示「太誠實」的拒絕原因。
18)度量與實驗
字段上的錯誤率(掩碼之前/之後)。
時間到完整表單和重新發送。
未成功插入(copipast)和「回滾」(undo)的比例。
線索/示例的CTR,自動完成的比例。
付款步驟/KUS上的Abandon率。
19) QA支票清單
輸入和caret
- 從緩沖區插入不會斷裂,空格/連字符會正確清除。
- Caret在自動格式後仍可預測。
本地和格式
- 金額允許','/';存儲在小單位中。
- 日期待定並確認;存儲在ISO中。
A11y
- 標簽和'aria-describedby'連接;'role='alert'用於關鍵。
- 對比度和焦環對應於AA。
安全性
- 敏感字段不被編譯/緩存。
- 在關鍵的步驟上具有相容性和回歸性。
UX
- Placeholder是一個示例,不是標簽;幫助者就在附近。
- 口罩不會阻止在移動上打印;正確的鍵盤(「inputmode」)。
20)設計系統中的文檔
Компоненты: `MaskedInput`, `MoneyInput`, `PhoneInput`, `OtpInput`, `IbanInput`.
面具令牌(長度/模板),caret/插入規則,數字/日期的本地化。
Gaids的隱私性(不用計算),可用性和自動格式vs blur。
「Do/Do n't」帶有實際示例和之前或之後的度量標準。
簡短摘要
口罩和表單在加速輸入、保持數據清潔和不幹擾時效果良好。格式化,在入口處規範化,以穩定的視圖存儲,考慮位置和可用性。然後,表格變得快速易懂-尤其是在敏感的支付,KYC和投註場景中。