:required和:optional仅依据HTML中required属性是否存在匹配,不响应JS动态修改、用户填写或disabled/readonly状态;仅对支持原生验证的控件(如text、email、select、checkbox、textarea)生效,hidden、button、div等无效。

:required 和 :optional 只看 HTML 里有没有写 required 属性,不看 JS 动态改没改、用户填没填、字段禁不禁用——写上了就匹配 :required,没写才可能进 :optional,但还得满足“本身支持原生验证”这个硬条件。
哪些元素能被 :required 或 :optional 匹配?
不是所有带 required 的标签都算数。只有参与浏览器约束验证(constraint validation)的控件才生效:
-
<input type="text">、<input type="email">、<input type="checkbox">、<select></select>、<textarea></textarea>→ ✅ 支持:required/:optional -
<input type="hidden">、<input type="button">、<button></button>、<div>、<code><fieldset></fieldset>→ ❌ 即使写了required,也完全不匹配 -
<input type="radio">组中,只有显式带required的那个<input>被单独匹配,不是整组联动 -
<input name="phone" required="false">→ 实际仍匹配:required -
<input name="email" aria-required="false">→:optional不读aria-required,照样不匹配 -
<input name="avatar" class="optional">→ class 名无效,CSS 伪类不认这个 -
input:not(:disabled):optional→ 只对可编辑的可选字段生效 -
input:not(:readonly):optional→ 再加一层只读过滤 -
input:required:disabled→ 即使禁用,仍匹配:required,这点要心里有数 -
input:required:invalid→ 空值且已失去焦点(或触发过校验)时生效 -
input:required:not(:placeholder-shown)→ 适合配合 placeholder 提示“已开始填但没填完” - 需要更精准控制(比如刚聚焦就反馈),得靠 JS 加 class,
:user-invalid兼容性太差(Safari 15.4+ 才支持)
:optional 没生效?大概率是误写了 required="false"
:optional 不认属性值,只认属性是否存在。只要 DOM 里有 required 这个字符串,哪怕写成 required=""、required="false"、required="anything",它都当必填处理,:optional 规则压根不会命中。
常见翻车写法:
立即学习“前端免费学习笔记(深入)”;
正确做法:真想标“可选”,就彻底删掉 required 属性。
disabled/readonly 字段也会走 :optional,容易误导用户
:optional 判断逻辑和字段是否可编辑无关。一个 <input disabled>,只要没写 required,就会匹配 :optional —— 导致你给“可选字段”设的浅灰背景、斜体字,也套在了不可编辑的字段上,用户可能误以为还能填。
安全写法是主动排除:
想响应填写状态?别指望 :required/:optional
这两个伪类是静态的,只反映 HTML 结构,不反映用户行为。空着的必填项不会自动高亮,填错也不会变色。
真要提示“该填没填”,得组合其他伪类:
最常被忽略的其实是 :disabled 的干扰,以及把 required="false" 当真——这两点一错,整个样式链就断了。


















