:read-only 未生效主因是元素未满足浏览器认定的“只读”条件:仅 <input>(非 hidden/checkbox 等)和 <textarea> 支持,且必须存在 readonly HTML 属性(如 <input readonly>),JS 需用 setAttribute('readonly', ''),Vue/React 中需确保 DOM 确实渲染该属性;Safari 15.4 前对 type="number" 有兼容性问题;推荐并列使用 input[readonly], input:read-only 以兼顾兼容性与语义;仅设 border: none 不足,须同步设置 padding、background-color、cursor: default 和 user-select: text;只读元素仍可获焦点,需手动加 tabindex="-1" 控制 Tab 流,且 :read-only 不影响表单验证,而 :disabled 会跳过验证且不提交;后端未返回 readonly 属性时伪类无效,须改用 class 控制;状态切换时易遗漏移除 tabindex="-1" 或重置 user-select,导致编辑态异常。

:read-only 为什么没生效?先确认元素真“只读”
伪类不触发,90% 是因为元素压根没进入浏览器认定的“只读”状态:readonly 必须是 HTML 属性,写成 <input readonly> 或 <input readonly=""> 都行;readonly="false" 也照样匹配(属性存在即生效)。
<select readonly>、<button readonly>、<div contenteditable="false"> 全都不匹配 —— :read-only 只认 <input>(非 hidden、checkbox 等)和 <textarea>。
- JS 动态设置时,用
el.setAttribute('readonly', ''),别只写el.readOnly = true;后者在 SSR 或初始渲染中可能不同步 - Vue/React 中确保最终 DOM 里真有
readonly字样,而不是仅靠响应式变量控制 - Safari 15.4 前对
type="number"有漏匹配 bug,不能单独依赖:read-only
input:read-only 和 input[readonly] 该选哪个?
优先写 input:read-only,但必须和 input[readonly] 并列使用:
在 Linux 上通过 Chrome 挂载/VNC 自动发布小红书长笔记。Agent 撰写标题和正文后执行 xhs_publish.sh --publish --submit,触发小红书发布。
-
input[readonly]兼容 IE9+,行为确定:只要属性在 DOM 里就命中 -
input:read-only是语义更准的伪类,但 Safari 旧版、某些安卓 WebView 会跳过匹配 - 两者并列写(如
input[readonly], input:read-only),既覆盖现代逻辑,又兜底旧环境
只设 border: none 会出问题?补全这三件事
只砍边框容易让输入框“塌掉”或文字贴边,必须同步调整其他属性:
立即学习“前端免费学习笔记(深入)”;
- 显式加
padding: 4px 8px(或按你设计系统统一值),补回被 border 占用的空间 - 设
background-color: #f9fafb(比:disabled的#f4f4f5略亮),强调“这是数据,不是锁死” - 用
cursor: default替代not-allowed,避免和禁用状态混淆;加user-select: text允许复制
容易被忽略的焦点与可访问性细节
只读输入框仍能获得焦点、响应 Tab 键,这点常被当成 bug 处理,其实是规范行为:
- 若查看模式下不想让用户停在只读字段上,得手动加
tabindex="-1" - 别忘了
input:read-only:focus或input[readonly]:focus,否则某些浏览器会显示默认 outline -
:read-only不影响表单验证(值仍会提交),而:disabled会跳过验证且不提交 —— 语义不能混 - 真正难处理的是后端返回的字段没带
readonly属性,前端却要按逻辑只读。这时候伪类完全无能为力,只能靠 class 控制
tabindex="-1" 或没重置 user-select,导致编辑态下无法选中文本。伪类本身很轻量,但配套的交互逻辑才是坑点。

















