:valid 和 :invalid 仅反映浏览器原生校验结果,需配合 required、type、pattern 等属性才能触发;无校验规则则状态恒定,且无法影响父元素或跨节点样式,异步校验须用 setcustomvalidity() 主动触发。

:valid 和 :invalid 本身不能“实现”校验逻辑,它们只是反映浏览器原生校验结果的视觉钩子——没加 required、type="email" 或 pattern,样式就永远不会触发。
为什么写了 :invalid 样式却没反应?
最常见原因是:表单控件压根没参与原生校验。浏览器不会凭空判断“对错”,必须显式声明约束。
-
<input type="text">永远:valid(包括空字符串),因为无校验规则 -
<input required>空值时初始即:invalid;填内容后变:valid -
<input type="email" value="a@">不会立刻:invalid,得等用户失焦或提交才计算 -
<textarea pattern=".{5,}"></textarea>必须带pattern才能被识别为可验证元素
如何避免一打开页面就红边框?
空的 required 输入框加载即 :invalid 是规范行为,不是 bug。延迟反馈需绕过这个默认时机。
- 用
input:not(:placeholder-shown):invalid:前提是加了placeholder,且用户至少输过一个字符 - 用
input.touched:invalid:JS 在blur或input事件里加touched类,再写对应规则 - 用
:user-invalid:Chrome 102+ / Firefox 119+ / Safari 16.4+ 支持,只在用户编辑过且失败时匹配,语义最准 - 别用
:focus:invalid强制显示——用户刚点进来还没输,红框反而干扰
怎么让 ✅ 图标只在真正合法时出现?
input:valid::after 很容易误触发:非 required 字段空值默认 :valid,图标一加载就挂着。
- 结构上必须用
<div class="input-wrapper"> <input><span class="checkmark"></span> </div>,并给 wrapper 设position: relative - 选择器写成
input:not(:placeholder-shown):valid + .checkmark,排除 placeholder 显示阶段 - 若字段允许为空,但只希望“有内容且合法”才显示 ✅,就得靠 JS:
el.value.trim() && el.checkValidity()成立时加is-valid类 -
type="number"要小心——输入"12."或"-"瞬间变:invalid,移动端闪动明显,建议改用type="text" pattern="[0-9]*"+ JS 解析
为什么父容器或 label 不跟着变色?
:valid 和 :invalid 是元素级伪类,作用域仅限于自身,无法向上影响父级或跨节点控制兄弟元素。
-
input:invalid + label只能控制紧挨在后面的label,且 HTML 顺序必须是 input 在前、label 在后 -
form :invalid可以选中所有无效子控件,但依然不能让包裹它的div.form-group变色 - 真要整组变色,必须用 JS:监听
input事件,调用el.checkValidity(),再根据结果给父容器加is-invalid类 -
:has(input:invalid)理论上可行,但 Safari 目前仍不稳定(截至 2026 年 7 月)
最容易被忽略的是:伪类状态永远滞后于 JS 校验。比如邮箱唯一性检查、密码强度异步验证,:invalid 压根不会响应——这些必须靠 setCustomValidity() + reportValidity() 主动触发,否则 CSS 就是摆设。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











