真正匹配 :read-only 的元素是 (非 hidden 类型)和 中显式声明 readonly html 属性的实例;、 不支持,js 设置 readonly = true 可能漏样式,disabled 元素完全不匹配。

:read-only 和 :read-write 能区分输入状态,但只对真实写了 readonly 属性的 <input>(非 type="hidden")和 <textarea></textarea> 生效;disabled 元素完全不匹配,JS 设置 el.readOnly = true 也不触发样式。
哪些元素真正匹配 :read-only?
浏览器只看 DOM 中是否存在 readonly 这个布尔属性,不关心 JS 是否锁了输入、也不管是否加了 disabled 或 contenteditable="false":
-
<input type="text" readonly>✅ 匹配 -
<textarea readonly></textarea>✅ 匹配 -
<input type="number" readonly>✅ 但 Safari ≤15.3 有漏匹配 bug -
<select readonly></select>❌ 不支持,伪类完全忽略 -
<button readonly></button>❌ 无效 -
el.setAttribute('readonly', '')✅ 推荐,确保属性写入 DOM -
el.readOnly = true⚠️ 多数浏览器识别,但 SSR 或首屏渲染可能漏样式
:read-write 不等于 “没加 readonly”
:read-write 是浏览器根据真实可编辑能力判定的状态,不是简单否定属性:
-
<input type="text">✅ 默认匹配(无readonly、无disabled、类型支持输入) -
<input type="radio">❌ 不匹配,即使没加readonly -
<input disabled>❌ 既不匹配:read-write,也不匹配:read-only,只走:disabled <div contenteditable="true"> ✅ 能匹配,但 Safari 15.4 前有兼容问题 <li><code><div contenteditable="false"> ❌ 规范说该匹配 <code>:read-only,但实际多数浏览器不认,得用[contenteditable="false"]和
:disabled共存时的样式优先级陷阱:disabled的权重天然高于:read-only,哪怕你把它写在后面,只要元素带disabled属性,:disabled样式一定生效:- 别让
readonly和disabled同时存在——语义冲突:readonly字段仍可聚焦、可复制、会提交;disabled则彻底禁用 -
:read-only默认允许文本选择,想禁止需显式加user-select: none - 只读输入框仍会接收 Tab 焦点,若查看模式下不想停在这里,得手动设
tabindex="-1" - IE 全系不支持这两个伪类,兜底建议用
input[readonly]+@supports selector(:read-only)包一层覆盖
最常被忽略的是:伪类只响应 HTML 属性,不响应 JS 行为。哪怕你绑了
oninput="return false"或preventDefault,只要没写readonly属性,:read-only就不会生效。- 别让











