:valid 和 :invalid 仅对含 required、type、pattern 等验证属性的表单控件生效,且需触发验证(如失焦、提交或调用 checkvalidity());初始状态依值合法性而定,动态更新需手动触发验证。

什么时候 :valid 和 :invalid 才会生效
这两个伪类只对有验证约束的表单控件起作用,不是所有 <input> 都能触发。必须满足:控件有 required、min/max、pattern、type="email" 等原生验证属性,且浏览器已完成一次验证尝试(比如用户输入后失焦、提交表单、或调用 checkValidity())。
常见误区是给 <input type="text"> 直接加 :invalid 样式却没反应——因为纯文本输入框默认无验证规则,不满足“可验证”前提。
-
<input required>✅ 触发:invalid(空时)和:valid(非空时) -
<input type="email" value="a@b">❌ 不触发(格式错误但未验证),需失焦或提交才计算状态 -
<textarea pattern=".{10,}"></textarea>✅ 有pattern就算可验证控件
:valid 和 :invalid 的样式优先级与作用范围
它们是伪类,权重等同于普通类选择器(如 .error),但低于内联样式和 ID 选择器。样式会直接作用于目标元素本身,不能跨层级影响父容器或兄弟节点。
想给整个表单项(含 label 和提示文字)变色?必须借助父容器配合属性选择器或 JS 辅助:
form :invalid {
border-color: #e53e3e;
}
/* 无法直接让 label 变红,除非 label 是 input 的相邻兄弟且用了 + */
input:invalid + label { color: #e53e3e; }
/* 更稳妥的做法是让 form 元素根据子项状态添加 class,靠 JS 控制 */
- 伪类样式不会自动继承,
input:invalid不会让其父<div> 变色<li>多个验证规则同时失败,仍只匹配一次 <code>:invalid,不区分具体哪条失败 - 初始加载时若值合法,
:valid会立即生效;空required输入框初始即:invalid
如何避免被浏览器默认验证气泡干扰体验
原生 reportValidity() 或提交触发的红色气泡提示,和你写的 :invalid 样式常冲突。用户看到边框变红,又弹出浮层,体验割裂。
解决方式很直接:关掉默认气泡,把反馈完全交给 CSS 和自定义提示:
input:invalid {
outline: none;
}
input:invalid:focus {
box-shadow: 0 0 2px rgba(229, 62, 62, 0.5);
}
/* 同时禁用原生验证提示 */
form {
onsubmit="event.preventDefault();"
}
/* 或更彻底:设置 novalidate 属性,自己用 checkValidity() + setCustomValidity() 控制 */
- 加
novalidate到<form></form>可全局禁用提交时的气泡 -
setCustomValidity('')清空自定义错误,才能让:valid正常回退 - 注意 Safari 对
pattern的兼容性较弱,建议配合title属性提供 fallback 提示
为什么有些输入框始终不匹配 :valid 或 :invalid
最常见原因是控件类型和值不匹配验证逻辑。比如 <input type="number" value="abc"> 在 Chrome 中会被视为空值(不触发 :invalid),而在 Firefox 中可能直接忽略该值、保持初始状态。
另一个隐蔽问题是空格处理:required 对 " "(纯空格)判定为无效,但某些框架或初始化逻辑可能悄悄 trim 了值,导致状态跳变。
-
<input type="url">必须以http://或https://开头才可能:valid -
<input min="1" value="0">初始即:invalid,但若 JS 动态设value = "1",需手动调用input.checkValidity()才刷新伪类 - 动态添加的表单控件,需确保插入 DOM 后再设置验证属性,否则部分浏览器不识别
伪类的状态更新不是实时的,它依赖浏览器的验证时机,这点容易被当成 bug。真正可控的反馈闭环,往往需要 input、blur、invalid 事件配合 checkValidity() 主动触发。











