:invalid 比 :required 更常用,因其在必填字段为空或值不合法时实时生效并覆盖 required 状态,而 :required 仅静态标记属性存在;配合 :not(:placeholder-shown) 可避免空状态误触发,实现轻量级视觉反馈。

required 属性本身不触发任何样式变化,必须配合 :invalid、:valid、:required 等伪类才能实现动态视觉反馈;单独写 required 只是让浏览器做提交拦截,不解决“用户看到错误”的问题。
为什么 :invalid 比 :required 更常用
:invalid 在元素值不符合约束(包括空值、类型错误、正则不匹配等)时立即生效,且对 required 字段天然覆盖——只要必填字段为空,它就自动进入 :invalid 状态。而 :required 仅标记“有 required 属性”,无论值是否合法,它都一直存在,无法区分“未填”和“已填错”。
-
:invalid是实时的、可响应的,适合做红框/图标提示 -
:required更像一个静态标签,适合做“* 必填”文字标识,但不能用于校验逻辑 - 注意:
:invalid在用户首次聚焦前就可能触发(尤其 Chrome),导致“未操作就报错”,需配合:user-invalid(较新,兼容性有限)或 JS 控制 class
required + :invalid 的最小可行样式组合
不用 JS 就能做出基础反馈,但要注意默认行为干扰:比如 input[type="email"] 在空值时也触发 :invalid,但用户可能还没输完。稳妥做法是限定作用域,并用 :not(:placeholder-shown) 过滤掉纯空状态(需 placeholder 配合)。
input:invalid:not(:placeholder-shown) {
border-color: #d32f2f;
}
input:valid {
border-color: #2e7d32;
}
input[required]::after {
content: " *";
color: #d32f2f;
font-size: 0.85em;
}
- 必须加
:not(:placeholder-shown),否则 placeholder 存在时仍会误标:invalid -
input[required]::after是纯视觉标注,不影响语义,比 JS 插入更轻量 - 不要依赖
:optional做反向样式,部分老浏览器不支持
表单提交时才校验?那你就错过了交互时机
浏览器默认只在 submit 事件触发完整校验,但用户需要的是“输完立刻知道”。这时得靠 input 或 blur 事件手动触发表单检查,再结合 checkValidity() 和 reportValidity()。
-
reportValidity()会弹原生提示气泡并返回布尔值,适合提交前兜底 -
checkValidity()只返回结果,不打扰用户,适合静默判断 - 别直接监听
input做实时校验——中文输入法下会误判(如拼音阶段就触发),建议用change+blur组合 - 若用
setCustomValidity(),记得清空错误信息:调用setCustomValidity('')才能恢复默认校验
真正难的不是写对伪类,而是平衡“即时反馈”和“不骚扰用户”。比如邮箱字段,输到 a@ 就标红,不如等失焦再验;而密码强度可以输三个字符就跑个简单规则。这些边界得根据字段语义定,不是一套 CSS 能包打天下的。











