:invalid伪类可自动选中未填的必填表单控件,依赖required属性,页面加载即生效;需配合: user-invalid区分初始与用户交互后状态,避免样式冲突,且不适用于自定义组件或hidden输入框。

用 :invalid 伪类选中未填的必填表单控件
浏览器原生支持 :invalid,只要元素有 required 属性且当前值为空(或不符合类型规则),就会自动匹配该伪类。它比手动 JS 监听更轻量、更及时,且兼容所有现代浏览器(包括 Safari 15.4+)。
注意::invalid 在页面加载时就生效,哪怕用户还没操作过——这对初始校验提示很关键。
-
<input required>、<select required></select>、<textarea required></textarea>都适用 - 不适用于自定义组件(如封装的
MyInput),因为它们没继承原生表单验证逻辑 -
type="number"空值时也触发:invalid,但输入 "abc" 同样触发,需结合:user-invalid区分
避免 :invalid 和 :user-invalid 混用导致样式冲突
:invalid 是“当前值无效”,:user-invalid 是“用户已交互过且仍无效”。很多开发者只写 :invalid,结果一进页面所有红框全亮,体验突兀。
推荐组合策略:
立即学习“前端免费学习笔记(深入)”;
- 初始状态只用
:invalid:not(:user-invalid)做弱提示(比如边框变浅灰) - 用户失焦或提交后,加
.touched类或切换为:user-invalid强提示(比如红色边框 + 错误文案) - 不要在同一个选择器里同时写
:invalid:user-invalid——语法错误,浏览器会整个忽略该规则
required 属性缺失或被 JS 移除会导致 :invalid 失效
:invalid 完全依赖 HTML 的 required 属性存在。常见翻车点:
- Vue/React 中用
v-model或value={xxx}控制表单,但忘了同步required属性(比如条件渲染时漏掉) - JS 动态移除了
required(例如切换表单步骤),但没清理对应样式逻辑 -
input[type="hidden"]带required不会触发:invalid(隐藏域不参与交互验证)
调试时直接检查元素是否真有 required="" 属性,而不是只看 JS 变量或 state。
需要兼容老浏览器时,只能靠 JS 补位
IE 10–11 不支持 :invalid,iOS Safari :user-invalid 支持不全。如果目标用户含这些环境,必须降级:
- 监听
blur和submit事件,遍历document.querySelectorAll('input[required], select[required]') - 对每个元素调用
checkValidity(),手动添加data-invalid属性 - CSS 改用
[data-invalid]而非:invalid - 注意:
form.checkValidity()返回false时,不会告诉你哪个字段错,得自己逐个查
真正难的不是写这段 JS,而是确保它和框架的响应式更新节奏一致——比如 React 中 state 更新后 DOM 还没重绘,checkValidity() 就可能拿到旧值。










