:read-only仅匹配含readonly属性(值为""或"readonly")的input/textarea,不匹配disabled或contenteditable="false"元素。

如何用 :read-only 选中真正只读的 <input>
直接说结论::read-only 只匹配 readonly 属性存在且值为 "" 或 "readonly" 的 <input>(或 <textarea>),**不匹配 disabled 状态,也不响应 contenteditable="false"**。很多开发者误以为它能覆盖所有“不能编辑”的情况,结果样式没生效。
常见错误现象:input:read-only { background: #eee; } 写好了,但加了 disabled 的输入框背景没变——因为 :read-only 根本不作用于 disabled 元素。
-
readonly是语义级只读:元素可聚焦、可选中文本、可提交表单值 -
disabled是功能级禁用:不可聚焦、不可交互、表单提交时被忽略 - 若想统一处理两种状态,需显式写成
input:read-only, input:disabled
为什么 input[type="number"] 有时不响应 :read-only
某些浏览器(尤其是旧版 Safari 和部分 Android WebView)对 type="number" 的 readonly 支持不一致:即使 DOM 中有 readonly 属性,:read-only 伪类可能不触发。根本原因是这类输入框内部控件逻辑干扰了原生只读状态识别。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 优先改用
type="text"+ 输入限制(如inputmode="numeric"+ JS 拦截非数字键)来规避兼容性问题 - 若必须用
number,用属性选择器兜底:input[readonly]:not([disabled]) - 避免依赖
:read-only做关键交互控制(比如仅靠它禁用按钮),应同步检查el.readOnly === true
:read-only 和 :disabled 的样式优先级怎么协调
两者无固有优先级高低,谁写在后面谁覆盖前面(同层 specificity)。但容易踩的坑是:给 :disabled 设了深灰背景,又给 :read-only 设浅灰,结果发现 readonly 输入框看起来像 disabled——因为它们都用了 background,而你忘了重置。
推荐做法:
- 把共用样式(如字体、边框)写在基础选择器里:
input - 只在
:read-only中设置“只读专属态”,比如加锁图标:background-image: url("lock.svg"); - 如果要视觉一致,统一用
input:read-only, input:disabled,但保留 JS 中对两者的语义区分(例如表单校验仍需知道是只读还是禁用)
Vue/React 中动态切换 readonly 时 :read-only 不更新?
不是 CSS 的问题,是框架绑定方式导致 DOM 属性未正确同步。比如 Vue 模板里写 <input :readonly="isReadonly">,当 isReadonly 为 false 时,Vue 默认移除 readonly 属性;但若你用 v-bind 绑定字符串 "readonly" 或空字符串 "",才会让属性存在,从而触发 :read-only。
正确写法示例:
<!-- ✅ 触发 :read-only --> <input :readonly="isReadonly ? '' : null"> <p><!-- ❌ 不会触发,因为属性被完全移除 --> <input :readonly="isReadonly">
React 同理:用 readOnly={isReadonly} 即可(注意 React 中属性名是 readOnly,首字母大写),它会正确映射为 DOM 的 readonly 属性存在与否。
最易被忽略的一点:服务端渲染(SSR)页面中,初始 HTML 若没带 readonly 属性,即使客户端 JS 后续加上,CSS 伪类也不会回溯匹配——必须确保初始 HTML 就有该属性,否则首屏样式就错位了。


















