HTML數字欄位輸入1.5卻無效:step怎麼設定

數量欄位用了input type=number,使用者輸入1.5,瀏覽器卻說不是有效值。既然是數字欄位,為什麼小數不行?常見原因是step:number欄位預設步階是1,值必須落在以步階基準開始的允許位置,而不是只要能解析為數字就有效。

需要半份、長度或小數單價時,先確定允許的精度與起點,再設定step。step不是顯示格式,也不是四捨五入工具。它參與原生約束驗證;真正的資料規則仍要在後端確認。

預設步階1,先看stepMismatch

以下input沒有min,也沒有初始value屬性,因此步階基準是0。用JavaScript設定目前值為1.5,再讀取有效狀態,可以把問題和「欄位是空的」或「超過最大值」分開。

<input id="quantity" type="number" name="quantity">
const quantity = document.querySelector('#quantity');
quantity.value = '1.5';
console.log(quantity.validity.stepMismatch);
// true
console.log(quantity.checkValidity());
// false

quantity.step = '0.5';
console.log(quantity.validity.stepMismatch);
// false
console.log(quantity.checkValidity());
// true

step改成0.5後,從0開始的0、0.5、1、1.5都符合這個步階。沒有max或其他限制,不代表只能在這幾個值裡選;它仍沿著相同間距延伸。若業務只能選固定幾種數量,可能使用選單或按鈕更清楚,不必把固定選項偽裝成自由數字輸入。

checkValidity會檢查其他適用的約束,不只step。看到false時,進一步看stepMismatch、rangeUnderflow、rangeOverflow等資訊,才知道是哪個條件不成立。瀏覽器顯示的驗證訊息會依語言與實作不同,不要只比對某一句錯誤文字。

min也會改變步階起點

步階是從基準起算。對number欄位,基準依序取有效的min、有效的value內容屬性,否則是0。這也是為什麼你把min加上去後,原本某個整數可能反而不符合step。

<input id="length" type="number" min="0.2" step="1">
const length = document.querySelector('#length');
length.value = '1.2';
console.log(length.validity.stepMismatch);
// false

length.value = '1';
console.log(length.validity.stepMismatch);
// true

min=0.2、step=1的允許位置是0.2、1.2、2.2等,並不是所有大於0.2的數字都可以。min限制下界,同時也提供步階起點;兩種作用需要一起考慮。若你的規則是「至少0.2,任何小數都可以」,應另外考慮step=any,而非保留預設1。

HTML裡的value屬性和使用者目前輸入的值也要分清楚。沒有min時,初始value內容屬性可能提供步階基準;之後單純改input.value,並不等於把那個HTML內容屬性一起改掉。排查時同時核對getAttribute(‘value’)與目前value,避免只看畫面上的字就推斷起點。

step=any不檢查步階,但其他規則仍在

若業務允許不限固定間距的數值,可以用step=any停用步階不匹配的檢查。min、max、required及數字解析等條件仍各自適用。any不是「所有輸入都有效」,也不會讓文字變成數字。

<input type="number" name="length"
       min="0.2" max="10" step="any" required>

這個欄位可接受範圍內的小數,不必對齊固定步階;空值仍因required無效,超過10仍超出範圍。若只是想接受兩位小數,可以先評估step=0.01是否符合業務步階,但它不強制畫面永遠顯示兩位,也不會自動把三位小數四捨五入。

例如1.5與1.50的數值相同,顯示要保留尾端零則是格式呈現的需求。數字輸入、金額顯示與後端儲存可以採不同處理方式,不必要求一個step屬性完成全部工作。貨幣資料的計算與儲存也要按系統的精度規則決定,不能只因瀏覽器通過就當成計算一定精確。

把畫面提示和真正規則對齊

如果HTML一開始寫了value=0.5,且沒有min,預設步階1會從0.5起算。此時1.5可能有效,反而1不符合步階。這與本文第一個沒有value內容屬性的input不同,並不矛盾。複製別人的表單時,若只改目前值而保留原本的value屬性,可能把原作者的步階基準也一併帶過來。

需要明確起點時,使用符合業務的min通常更容易讀懂。像允許0.5份、1份、1.5份,可以設min=0.5、step=0.5;若數量至少1份但之後可半份增加,就改成min=1、step=0.5。兩個設定都接受某些小數,最低允許值卻不同。不要只為了讓某個測試數字過關而挑一個任意min。

另外,電話、郵遞區號或商品編號即使只含數字,也不一定適合type=number。它們通常是識別文字,而不是可以加減步階的數值;前置零可能有意義。遇到這類欄位應按資料用途選擇輸入類型,不能用step=any來補救所有「看起來是數字」的欄位。

資料回填也值得測一次。後端傳回字串1.50、前端設定目前value後,畫面可能呈現不同格式,但有效狀態仍要看數值與約束。若驗證失敗,保留使用者輸入並指出允許的步階,比默默改成另一個數字更清楚。需要自動調整數值時,應先讓使用者理解調整規則,再確認送出的值就是畫面最後顯示的值。

欄位旁可以直接說明「每次以0.5為單位」或「長度介於0.2至10」。比起送出後才看到瀏覽器提示,使用者在輸入前就知道允許範圍會更容易填寫。若有單位,例如公尺或份數,也應放在可理解的位置,避免1.5到底代表什麼都不清楚。

當欄位有錯誤時,不要為了讓送出按鈕能按就把所有約束移除。先確認業務到底允許1.5,還是只能輸入整份;前者要修step,後者要修提示與選擇方式。技術欄位設定應反映真正規則,不能由錯誤訊息反過來決定產品能接受什麼。

也要注意空值的處理。沒有required時,空的number欄位通常不會因step而無效;但valueAsNumber可能是NaN。需要區分未填和零,不能直接用真假判斷把0當成沒有填。範例只檢查步階,不代表已完成所有輸入資料的解析與必填檢查。

用幾個邊界值驗證,再檢查後端

number欄位不支援pattern約束,不能加一段正規表示式就要求固定小數格式。若業務需要的其實是某種文字格式,應重新評估欄位類型與解析流程;若需要的是數值步階,則使用step及範圍約束,再由後端核對同一套規則。

本機Chromium案例驗證了預設step下1.5無效、step=0.5下1.5有效,以及min=0.2、step=1時1.2有效而1無效。案例讀取的是原生validity狀態,不是憑欄位外觀推測,也沒有對正式網站提交資料。

自己的表單可測起點、起點加一個步階、兩格中間值、min以下與max以上,再測空值及合法零值。最後透過實際送出流程查看請求與後端驗證結果,確認前後端規則相同。瀏覽器驗證可以改善填寫體驗,但使用者仍能自行建立請求,所以後端不能省略範圍與精度檢查。

如果某個數字仍與預期不同,先把元素目前的min、max、step和value內容屬性記下來,縮小到一個input重現。框架可能在更新畫面時重新設定屬性,或你讀取的不是正在輸入的那個欄位。排除這些來源後,再看步階與基準,不要直接用CSS換顏色掩蓋無效狀態。

參考資料

原文鏈接:https://wntheme.com/html-number-step-mismatch/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?