數量欄位用了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狀態,不是憑欄位外觀推測,也沒有對正式網站提交資料。...
2026-10-04 51 0
文尼先生 2026-10-04

通知欄位要填兩個Email,第一個地址正常,一加第二個就被瀏覽器擋住,先看input是否有multiple。一般type="email"只接受一個地址;加上multiple後,可接受以逗號分隔的地址清單。分號不是這個原生欄位的分隔符號,即使某些郵件軟體使用分號,也不能直接套用。 這個設定只處理瀏覽器可判斷的格式,不證明地址存在、能收信或由填寫者持有。網站要真正把通知寄到這些地址,還需要後端解析、權限與寄送流程。先把輸入規則說清楚,訪客才不會把原本可用的兩個地址反覆修改成不同格式。 一個地址與多個地址的欄位不同 <label for="emails">通知地址</label> <input id="emails" name="emails" type="email" multiple> <p>多個地址請以逗號分隔。</p> 這段把通知地址設成選填。如果至少要填一個地址,再加required。不要只在提示文字寫「可以填多個」,卻保留沒有multiple的input;瀏覽器不知道你的說明文字,仍會按單一地址的規則判斷。 例如[email protected]與[email protected]這兩個合成地址,可組成[email protected],[email protected]。寫成[email protected];[email protected]則不能用同樣方式通過。畫面提示最好直接展示分隔方式,避免訪客從別的系統貼上一整串時才發現不符合。 multiple也不是把資料自動提交成兩個相同name的欄位。這個input仍有自己的value,內容是一段地址清單。後端不能以為已拿到一個陣列,直接迴圈寄送;應按格式解析,再對每個項目進行你的資料驗證。 用typeMismatch核對格式問題 const input = document.querySelector('#emails'); console.log(input.value); console.log(input.validity.typeMismatch); console.log(input.validity.valueMissing); console.log(input.checkValidity()); 在Chromium154的獨立頁面裡,沒有multiple時填兩個逗號分隔的地址,typeMismatch為true,欄位無效。加上multiple後,同一段字串的typeMismatch變成false,欄位有效。改用分號時,typeMismatch又變為true。 兩個地址之間的逗號後即使有一般空白,瀏覽器也會依email多值規則處理。在這組案例中,[email protected], [email protected]的value整理為沒有分隔後空白的形式,並通過驗證。這不表示任意奇怪字元都會被清理,也不要依賴前端去修正一份未知格式的地址名單。 檢查時可以在網路面板看真正送出的值,再和後端接收內容比較。若程式又對value做了替換或合併,問題可能出在你的轉換流程,而不是瀏覽器原生email驗證。測試用合成地址即可,不需要把真實客戶信箱放到公開截圖裡。 空欄位由required決定 沒有required時,空字串不會單靠type=email就被判成錯誤。加了required後,空值在本例的valueMissing為true,checkValidity為false。typeMismatch和valueMissing回答不同問題:前者是格式不符合,後者是必填值缺席。 因此「格式沒錯」不能代替「有填地址」。如果後端要求至少一位收件人,應明確驗證數量,不要只檢查所有已提供的項目是否看似Email,讓空清單也走到寄送流程。相反,選填通知功能則應允許使用者不提供地址,而不是暗中套入一個預設收件人。 加pattern時還有自己的限制要核對,不能假設它與multiple組合就自動表達所有公司信箱政策。像只允許某個網域、限制收件人數、禁止重複地址,這些是功能規則,應在後端有明確檢查與錯誤訊息。 後端要按每個地址處理 如果你的契約使用逗號清單,後端可以先拆分,再清理各項外圍空白,檢查每個值與總數。收到只有逗號、某項空白、任一地址格式錯誤時,應按既定規則拒絕或提示修正,不能只取第一項便宣稱其餘輸入已經處理。 收件人上限也應與介面一致。如果功能最多允許三個地址,提示應說明上限,後端則在寄送前真正拒絕超過的輸入。不要讓前端能填二十個,後端悄悄只寄前三個;使用者看不到被忽略的地址,容易把沒有收到信誤認為系統故障。 對重複地址要先決定是否合併。這裡的示範沒有提供一套通用Email正規化規則,因為地址的大小寫與服務商特殊別名可能有自己的限制。先依你的寄送服務與資料契約處理,不要為了去重把不同地址擅自改成同一個。 格式通過,不等於驗證收件人 瀏覽器不能只憑字串確認信箱是否存在。即使後端格式驗證也通過,仍可能是拼錯、停用或無法接收的地址。需要確認使用者持有信箱時,應設計適當的確認信流程;需要發送業務通知時,則要處理寄送回應與失敗紀錄。 新增多地址還可能改變通知範圍。原本只通知登入會員,若改成讓人任填多個地址,就應確認哪些資訊能寄出、誰有權新增收件人。不能因為這是一個HTML屬性修改,就忽略後端原本的資料權限。 若你不需要多收件人,保留單地址欄位反而清楚。multiple適合真的會按清單處理的功能,不宜為了讓一段錯誤輸入「看起來通過」就加上去。介面接受的內容應和後端能處理的內容一致。 提示要指向輸入方式 當格式錯誤時,提供「多個地址請用逗號分隔」比只說「資料錯誤」有用。若能指出某一項不符合,也要保留其餘已填內容,讓使用者只修正那一項。不要每次送出失敗就清空整個通知名單,逼人從頭貼上。 也可以考慮把每個地址做成獨立可編輯欄位,但那是另一種資料結構與操作設計。這篇先保留原生email多值欄位,幫你確認為何兩個地址會被擋。若之後改成多欄位或標籤式輸入,應重新核對鍵盤操作、刪除和提交資料,不沿用這次單一input的結論。 用六種輸入確認修改 若地址來自貼上,測試時也加入前後一般空白,確認畫面提示沒有誤導。不要把其他不可見字元或任意分隔符一律移除;清理過度可能把兩個原本分開的地址黏成一項。遇到不支援格式時,明確要求修改,比悄悄猜測更容易保住使用者要填的內容。 至少保存單地址、兩個逗號地址、分號地址、含逗號後空白、空選填與空必填的測試。這六種輸入能幫你分辨multiple、格式和required的責任。再把同一組合成資料送到測試後端,確認它真的逐項解析、驗證與回報。 最後核對錯誤提示和功能文件:訪客看到的是逗號規則,後端也應使用相同規則。不要讓HTML驗證、前端清理及後端寄送各自接受不同格式。維持同一套輸入約定,比不斷新增例外字元更容易讓通知功能穩定。 參考資料 HTML email HTML multiple typeMismatch valueMissing HTML標準:email
2026-10-05 51 0
文尼先生 2026-10-05
顯示驗證碼
沒有帳號?註冊  忘記密碼?