:invalid伪类在页面加载时即匹配空required字段,因浏览器按HTML5规范判定其非法;需配合placeholder与:not(:placeholder-shown)实现“已输入且错误”状态,纯CSS可行但依赖校验属性和placeholder存在。

直接用 :invalid 伪类就能加失败样式,但不加约束或不处理初始状态,它会一加载就标红所有空 required 字段——这不是 bug,是浏览器按规范执行的结果。
为什么 :invalid 一打开页面就生效
因为 required 字段初始为空,浏览器判定为非法值,:invalid 立即匹配。你没写错,是 HTML5 规范本就如此。
- 必须给
input加placeholder属性,否则:not(:placeholder-shown)永远不成立 -
:invalid:not(:placeholder-shown)是最轻量的“已输入但错误”判断方式,不依赖 JS - 旧版 Safari 对
:user-invalid更友好,但它在 Chrome 102+ / Firefox 119+ / Safari 16.4+ 才稳定支持,不能当默认方案 - 如果用了
form默认提交逻辑又没加novalidate,浏览器会在submit时强制校验并跳转,掩盖实时反馈效果
怎么让 :invalid 只在用户输错后才触发
核心是区分「未交互」和「已输入且非法」。纯 CSS 能做到,但有前提条件。
- HTML 必须带校验属性:
required、type="email"、pattern="[0-9]{6}"(注意:不要写斜杠) - 必须设
placeholder,哪怕只是空格:<input placeholder=" "> - 推荐写法:
input:invalid:not(:placeholder-shown) { border-color: #dc3545; } - 别用
input:focus:invalid—— 它在用户刚聚焦还没输时就可能匹配空字段,体验反更差 - 想兼容更老浏览器?改用 JS 监听
blur或input,手动加is-invalid类,再写.is-invalid样式
Less 中写 :invalid 样式容易踩的坑
Less 编译规则会让一些看似合理的写法彻底失效。
立即学习“前端免费学习笔记(深入)”;
-
&:focus:invalid在 mixin 外层或变量块里直接写会失焦,编译后变成:focus:invalid(无元素名),浏览器忽略 - 正确写法必须挂载在具体选择器下:
input { &:focus:invalid { border-color: #dc3545; } } - 用
.form-group input { &:focus:invalid { } }会导致最终选择器为.form-group input:focus:invalid,权重高但易被组件库覆盖 - 更稳的写法是属性选择器:
input[required]:invalid,意图清晰、权重明确 - 别用
when守卫做运行时状态分支——它是编译期逻辑,无法响应用户输入变化;.form-control.is-invalid这种 class 驱动才是正解
边框变色要即时,别加 transition
错误反馈需要明确、不拖沓。加过渡动画在 :invalid 上反而破坏体验。
- 用户刚敲一个字母就看到边框渐变红,会产生压迫感
- 可以给
:focus或:valid加transition提升正向反馈,但:invalid建议显式重置:input:invalid { transition: none; } - 注意优先级:如果某条规则写了
border-color: red且比var(--border-color)更具体,CSS 变量就会被覆盖 - 调试时先看 computed styles 中最终生效的
border-color来源,内联样式会直接压过var()
真正关键的不是怎么写 :invalid,而是 HTML 是否带校验属性、placeholder 是否存在、以及是否理解它的触发时机——它不校验,只反映浏览器内置校验的结果;而这个结果,取决于你有没有给 input 加 required、type="email" 或 pattern。


















