Back

开发者常忽略的原生 HTML 验证属性

开发者常忽略的原生 HTML 验证属性

你正在编写自定义 JavaScript 来验证表单,而这些工作 HTML 本可以原生处理。大多数前端开发者都知道 requiredpattern,但平台提供的功能远不止这些——这些属性可以减少代码量、改善可访问性,并在无需框架依赖的情况下创建更好的用户体验。

本文介绍了你可能忽略的 HTML 验证属性,以及使原生表单验证真正有用的 CSS 和 JavaScript 特性。

核心要点

  • form 属性允许控件通过 ID 与表单关联,无论 DOM 位置如何,从而消除复杂的包装结构。
  • 按钮级属性如 formactionformmethodformnovalidate 让单个表单根据提交按钮的不同而表现不同。
  • 现代 autocomplete 标记(new-passwordone-time-codewebauthn)提高自动填充准确性并触发浏览器功能,如密码生成器。
  • CSS :user-invalid 解决了”页面加载时显示红色边框”的问题,仅在用户交互后显示错误。
  • 约束验证 API(setCustomValidity()checkValidity()reportValidity())在原生验证需要增强时提供编程控制。

form 属性:表单外的控件

需要在页面头部放置提交按钮,而表单位于主内容区?form 属性允许任何控件通过 ID 与表单关联,无论 DOM 位置如何。

<form id="checkout">
  <input type="email" name="email" required>
</form>

<button type="submit" form="checkout">完成购买</button>

这消除了包装器的复杂操作,并且适用于 input、button、select 和 textarea 等元素。

你应该了解的按钮级覆盖

单个表单可以根据提交按钮的不同而表现不同。这些属性会覆盖父表单的设置:

  • formaction — 提交到不同的 URL
  • formmethod — 使用 GET 而非 POST(或反之)
  • formenctype — 更改文件上传的编码方式
  • formtarget — 在新标签页中打开响应
  • formnovalidate — 完全跳过验证

formnovalidate 属性值得特别关注。它对于”保存草稿”按钮至关重要,因为在这种情况下不完整的数据是可以接受的。

带有有用错误消息的模式验证

pattern 属性接受正则表达式,但浏览器默认显示通用错误。将其与 title 配对以提供上下文:

<input type="text" 
       pattern="[A-Z]{2}[0-9]{6}" 
       title="格式:两个字母后跟六位数字(例如,AB123456)">

注意:当在 type="email" 等输入上设置 multiple 时,模式会应用于每个单独的值,而不是整个逗号分隔的字符串。

现代 autocomplete 标记

除了 onoff,autocomplete 接受语义标记以提高自动填充准确性:

  • autocomplete="new-password" — 触发密码生成器
  • autocomplete="one-time-code" — 针对短信验证进行优化
  • autocomplete="webauthn" — 标识通行密钥凭据字段

这些标记减少了摩擦,并向浏览器和密码管理器传达意图(请参阅 HTML 规范中的完整标记列表和 MDN 的 autocomplete 文档)。

用于国际化的 dirname 属性

在支持从右到左语言时,dirname 会自动提交文本方向和值:

<input type="text" name="comment" dirname="comment.dir">

表单会同时提交 comment(值)和 comment.dir(ltrrtl)。这对于正确渲染用户生成的内容至关重要。

readonly 的细微差别

一个常见的误解:readonly 字段参与表单提交,但在验证方面表现不同。它们会提交值并且可以获得焦点。

然而,在现代 HTML 中,readonly 控件被排除在约束验证之外。这意味着在当前的常青浏览器中,requiredpatternminmax 等属性在 readonly 输入上会被验证忽略。

如果你需要显示一个值而不允许编辑不提交它,disabled 通常是更好的选择——尽管禁用字段不会提交其值。

用于现代表单用户体验的 CSS :user-invalid

经典的 :invalid 伪类会立即触发,在用户交互之前就显示错误。较新的 :user-invalid 仅在用户交互后匹配——解决了”页面加载时显示红色边框”的问题。

input:user-invalid {
  border-color: #dc3545;
}

input:user-valid {
  border-color: #28a745;
}

这在无需 JavaScript 时序逻辑的情况下创建了更好的用户体验。浏览器支持现在在常青浏览器中已经很稳定(请参阅 MDN 上的 :user-invalid)。

约束验证 API

当原生验证需要增强时,约束验证 API 提供编程控制:

  • checkValidity() — 返回布尔值,失败时触发 invalid 事件
  • reportValidity() — 返回布尔值并显示原生错误 UI
  • setCustomValidity() — 设置自定义错误消息
const password = document.querySelector('#password');
const confirm = document.querySelector('#confirm');

confirm.addEventListener('input', () => {
  confirm.setCustomValidity(
    password.value !== confirm.value ? '密码必须匹配' : ''
  );
});

调用 setCustomValidity('') 以清除错误——传递任何非空字符串都会将字段标记为无效。

原生验证的不足之处

原生验证处理大多数情况,但有其局限性:

  • 跨字段验证(密码确认)需要 JavaScript
  • 错误消息样式由浏览器控制
  • 复杂的异步验证(用户名可用性)需要自定义代码

策略是:使用 HTML 验证属性作为基线,使用 CSS :user-invalid 进行样式设置,并仅在必要时添加约束验证 API。

结论

原生表单验证已经显著成熟。本文介绍的属性——form、按钮级覆盖、dirname、现代 autocomplete 标记——在默认情况下改善可访问性的同时,消除了大量自定义 JavaScript。

审查你现有的表单。你可能会发现 HTML 可以原生处理的验证逻辑,以及 CSS :user-invalid 可以在不需要任何事件监听器的情况下解决的用户体验问题。

常见问题

原生验证错误气泡的样式选项有限,由浏览器控制。你无法直接使用 CSS 对其进行样式化。对于自定义样式的错误消息,你可以在表单上使用 novalidate 属性禁用自动验证 UI,然后使用约束验证 API 检查有效性并显示你自己的错误元素。validationMessage 属性让你可以访问浏览器生成的错误文本。

是的,原生验证属性在框架中有效,因为它们渲染标准 HTML。然而,框架通常以不同的方式管理表单状态,这可能与原生验证冲突。许多开发者使用 novalidate 属性并通过框架状态处理验证。你仍然可以在组件中以编程方式利用约束验证 API 来实现混合方法。

两种方法都返回一个布尔值,指示元素是否通过验证约束。区别在于副作用:checkValidity() 仅在失败时触发 invalid 事件,而 reportValidity() 还会显示浏览器的原生错误消息 UI。当你想静默检查有效性时使用 checkValidity(),当你想让浏览器向用户显示错误反馈时使用 reportValidity()。

你无法仅使用 HTML 属性验证两个字段是否匹配。这需要 JavaScript。通过向确认字段添加 input 事件监听器来使用约束验证 API,然后在值不同时调用 setCustomValidity() 并传入错误消息,或在值匹配时传入空字符串。这将你的自定义逻辑与原生验证系统集成在一起。

Gain control over your UX

See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay