:valid/:invalid 伪类不实时更新,需js调用checkvalidity()触发;html必须配置required、type="email"等约束才生效;推荐用:user-invalid或touched类实现用户交互后反馈,避免初始全红。

:valid 和 :invalid 本身不实时,浏览器只在失焦、提交或手动调用 checkValidity() 后才更新状态;所谓“实时反馈”,必须靠 JS 主动触发校验,否则一加载就红、输一半就闪,全是规范行为,不是 bug。
为什么写了 :invalid 却没反应?
根本不是 CSS 写错了,而是 HTML 没配对验证属性:<input type="text"> 永远 :valid——它没有内置规则。
- 必须至少带一个约束:如
required、type="email"、pattern="[0-9]{6}"(注意:不加前后斜杠)、minlength="2" -
type="phone"这类自定义类型会被降级为text,完全失去校验能力 -
pattern值写成"/[0-9]{6}/"❌,正确是"[0-9]{6}"✅ - 空的
required字段在 DOM 渲染完成瞬间就是:invalid,这是 HTML 规范定义的行为
怎么避免页面一打开就全红?
初始红框来自空 required 字段被立即判为无效,解决关键是延迟视觉反馈时机,而非压制伪类本身。
- 现代方案:
input:user-invalid—— 只在用户编辑过且当前值不满足约束时匹配,Chrome 102+ / Firefox 119+ / Safari 17.4+ 支持 - 兼容方案:
input.touched:invalid,监听input或blur后加touched类 - 折中技巧:
input:invalid:not(:placeholder-shown),但前提是该字段设置了placeholder属性 - 绝对别用
:focus:invalid做唯一判断——用户聚焦后删空,依然触发,体验断层
如何让边框变色不盖掉 :focus 高亮?
直接写 input:focus:invalid { border-color: red; } 会吃掉 focus 的 outline 或 box-shadow,尤其在 Windows 高对比模式下 outline 可能不可见。
- 分离视觉维度:用
border-color表达验证结果(合法绿 / 非法红),用box-shadow表达聚焦状态(比outline更稳) - 显式组合规则:
input:focus { box-shadow: 0 0 0 2px #3182ce; }+input:invalid:not(:focus) { border-color: #e53e3e; }+input:focus:invalid { border-color: #e53e3e; } - 别给
:invalid加transition——错误反馈需要明确即时;若整体有过渡,单独重置input:invalid { transition: none; }
怎样做到“每敲一个键都变色”?
:valid/:invalid 不响应 input 事件,浏览器默认只在失焦或提交时校验。所谓实时,必须靠 JS 主动触发。
- 最简可行做法:
el.addEventListener('input', () => el.checkValidity());—— 注意是input事件,不是change - 移动端软键盘数字键常不触发
blur,若保留type="number",需额外监听change或表单提交 - 自定义校验(如用户名是否已存在)必须调用
setCustomValidity("错误信息")或setCustomValidity(""),漏一次,状态就卡死 -
type="number"对中间态极度敏感(输入"-"、"."、粘贴乱码都会立刻:invalid),推荐改用type="text"+inputmode="numeric"+ JS 校验
setCustomValidity() 调用不及时、checkValidity() 绑定遗漏、或 user-invalid 在旧环境未降级,都会导致视觉反馈与实际校验结果脱节。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











