:read-only仅匹配HTML中真实存在readonly属性的<input>(文本类type)和<textarea>,不响应JS赋值或disabled;需手动加user-select: none和cursor: default等样式提示。

如何用 :read-only 伪类精准命中只读输入框
浏览器只认 HTML 中真实存在的 readonly 布尔属性,不是 JS 赋值的 el.readOnly = true,也不是写了但没生效的 setAttribute('readonly', '')。只有写在标签里或用 el.setAttribute('readonly', '') 设置的,才会触发 :read-only 匹配。
它只对 <input type="text">、<input type="email">、<textarea> 生效;<select readonly> 或 <input type="checkbox" readonly> 完全不匹配,样式白加。
常见错误:
- 写成
input:read-only { ... }却忘了<input>实际没带readonly属性 - 在 Safari ≤15.3 中对
<input type="number">使用:read-only,有漏匹配 bug - 和
:disabled写在同一选择器里,结果:disabled优先级更高,:read-only样式被覆盖
readonly 默认不灰化,必须手动加 CSS 提示
默认情况下,readonly 输入框和可编辑状态长得一模一样,用户点进去才发现不能改——这不是体验问题,是功能误导。光靠颜色区分不可靠(色弱用户难识别),得组合多个视觉信号。
立即学习“前端免费学习笔记(深入)”;
推荐写法:
input:read-only,
textarea:read-only {
background-color: #f9f9f9;
border-color: #ddd;
cursor: default;
user-select: none;
}
注意:user-select: none 不是 :read-only 自带的,必须显式加,否则用户仍能双击选中文本(这和“只读”语义冲突);cursor: default 比 not-allowed 更稳妥,后者在部分屏幕阅读器中可能误报为“操作失败”。
React/Vue 中容易漏掉的 DOM 细节
框架模板里写 readOnly={isReadonly}(React)或 :readonly="isReadonly"(Vue)只是声明属性,最终是否出现在渲染后的 DOM 上,决定样式能否生效。
检查方法:打开 DevTools,看元素上有没有真实的 readonly 属性。没有?那 :read-only 选择器根本不会起作用。
典型翻车点:
- React 中写成
readonly={isReadonly}(小写 r),属性名拼错,JSX 不报错但不渲染 - Vue 中用
v-bind:readonly但绑定的是字符串"true"而非布尔值,导致属性存在但值为readonly="true",部分旧浏览器不识别 - 动态切换时,JS 改了
el.readOnly但没同步更新 class 或触发重绘,CSS 未重新计算
IE 和老 Safari 的 fallback 怎么写才可靠
IE 全系不支持 :read-only,Safari ≤15.3 对某些 input 类型有兼容问题。别指望用户都升级,得兜底。
最稳方案是用属性选择器替代伪类:
input[readonly],
textarea[readonly] {
background-color: #f9f9f9;
border-color: #ddd;
cursor: default;
user-select: none;
}
这个写法在所有支持 HTML4 的浏览器里都有效,且不需要 JS 检测支持性。如果项目还要求支持 IE8 及更早版本,再加一条 .readonly-input class 手动打标,但 2026 年基本不用了。
真正容易被忽略的是:即使用了 fallback,也得确保 readonly 属性真出现在 DOM 上——否则连属性选择器都匹配不到。



















