:valid 和 :invalid 伪类仅响应 html 原生校验属性(如 required、type、pattern),不响应 js 修改;需配合 :placeholder-shown 避免初始红框,自定义校验须调 setcustomvalidity("") 重置状态,:user-invalid 更契合提交后反馈。

:valid 和 :invalid 伪类本身就能改样式,但直接写 input:invalid { border-color: red; } 很可能一打开页面就满屏红框,或者输错也不变色——问题不在 CSS 写法,而在 HTML 约束没配对、浏览器状态没触发、或你误以为它“实时响应输入”。
为什么写了 :invalid 却没反应?
根本原因是:这两个伪类只认 HTML 原生校验属性,不认 JS 改 value 或加 class 的操作。
- 必须带至少一个验证约束:比如
required、type="email"、pattern="\d{6}"、minlength="2";type="text"单独存在时永远是:valid - 空的
required输入框在页面加载后立刻匹配:invalid,这是规范行为,不是 bug - Safari 在未聚焦前常不计算状态;Chrome/Firefox 可能等到
blur才更新,导致 input 过程中样式“卡住” - JS 调用了
setCustomValidity("xxx")却没调reportValidity(),伪类不会刷新
怎么避免一开页就红框?用 :placeholder-shown 控制时机
初始空值 + required → 立刻 :invalid,体验差。关键是让错误样式只在“用户真输过又输错”时才出现。
- 给输入框加
placeholder="请输入邮箱" - CSS 写成:
input:invalid:not(:placeholder-shown) { border-color: #f33; } - 这样:空着且显示 placeholder 时,不触发红框;用户输内容再删空/输错,才标红
- 注意:
:placeholder-shown在 Safari 15.4+、Chrome 47+、Firefox 51+ 支持,旧版需降级
JS 校验后 :invalid 不更新?漏了 setCustomValidity("")
自定义逻辑(如用户名是否重复)必须通过表单 API 告诉浏览器状态,否则伪类完全无感。
- 校验失败时:
input.setCustomValidity("该用户名已被注册") - 校验通过时:
input.setCustomValidity("")—— 这一步极易遗漏,不写就永远卡在:invalid - 想立刻看到样式变化,补
input.reportValidity();但会弹默认气泡,生产环境建议只在submit时用 - 仅调
checkValidity()返回布尔值,不会刷新 CSS 状态
提交后才高亮错误?别只靠 :invalid,试试 :user-invalid
:invalid 在输入中就可能激活,而用户真正需要的是“我点提交了,哪里错了”的反馈。
-
:user-invalid(Chrome 102+ / Firefox 119+)只在用户 focus → blur 过且验证失败时匹配,更符合提交后场景 - Safari 当前不支持,需降级:点击提交按钮时给
form加data-submitted属性,CSS 写form[data-submitted] input:invalid - 表单
reset()会清空原生验证状态(:invalid消失),但不会清除你手动加的 class,记得同步清理
最常被忽略的其实是浏览器对“空值”的处理差异:Safari 可能在删空后把 required 字段判为 :valid,而 Chrome 仍视为 :invalid。不实际在目标浏览器里输几次、blur 几次,光看文档根本发现不了这个问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











