:placeholder-shown匹配的前提是元素有placeholder属性、input.value.trim()===""且浏览器正渲染占位符文本;任一条件不满足即失效,常见原因包括不可见字符、type="number"清空残留、safari≤15.3兼容性缺陷及placeholder属性缺失。

为什么:placeholder-shown在输入后还匹配
它根本不是“输入后还生效”,而是 placeholder 实际没消失——伪类只响应视觉状态,不响应 value 变更本身。浏览器判断“是否显示占位符”有一套独立逻辑,和你写的 input.value 不完全同步。
-
input.value是空字符串"",但 DOM 中有全角空格、零宽空格\u200b或换行符\n:这些字符肉眼不可见,但会让 placeholder 隐藏失败,:placeholder-shown继续匹配 - 用了
type="number"且初始值是"0"或数字0:清空后部分浏览器仍渲染 placeholder(尤其旧版 Chrome),导致伪类不退出 - 用户聚焦后快速失焦,但未触发重绘:Safari ≤15.3 常见,伪类状态滞后,
input.value = ""后需手动input.blur()或强制重排 - HTML 里写了
placeholder=""(空字符串):规范要求此时不渲染 placeholder,但某些浏览器仍当作“有占位符”处理,造成伪类误判
:placeholder-shown 的触发条件比你以为的更严格
它必须同时满足三个条件才匹配:元素有 placeholder 属性(哪怕值为空)、input.value.trim() === ""、且浏览器当前正在渲染 placeholder 文本。缺一即失效,但反过来——只要任一条件没断开,它就继续生效。
- 漏写
placeholder属性::placeholder-shown永远为 false,哪怕value是空的 -
input.value = " "(一个半角空格):trim()后为空,但浏览器不认为这是“空”,placeholder 不显示 → 伪类不匹配 - 用 JS 设置
input.value = ""后没调用input.dispatchEvent(new Event('input', { bubbles: true })):部分浏览器不会重算伪类状态 -
type="date"或type="file":原生控件接管渲染,placeholder 常被忽略,伪类基本无效
怎么验证它到底该不该生效
别靠肉眼猜,直接查浏览器 devtools 里的 computed styles:展开 :placeholder-shown 规则,看它是否出现在“Matched CSS Rules”里。再点开 Elements 面板,检查对应 input 元素的 value 和 placeholder 属性值,以及是否真有 placeholder 文本浮现在输入框里。
- 用
console.log(input.value, input.value.length, input.value.trim().length)看实际内容 —— 很多“看起来空”的值其实含不可见字符 - 临时加一行 debug 样式:
input:placeholder-shown { outline: 2px solid red !important; },确认是否真被选中 - 禁用所有 JS,纯 HTML + CSS 测试:排除事件监听或动态赋值干扰
旧版 Safari 的兼容性坑最隐蔽
Safari ≤15.3 对 :placeholder-shown 的实现是残缺的:它可能在输入后不退出匹配,或聚焦时仍保持激活。这不是你 CSS 写错了,而是 WebKit 内核没按规范走。Autoprefixer 加前缀没用,因为 Safari 原生就用这个伪类名,不存在 ::-webkit-placeholder-shown 这种变体。
- 必须用 JS 补位:
input.addEventListener('input', () => { input.classList.toggle('placeholder-shown', input.value.trim() === ''); }) - 初始化时就得同步一次:
updateState(),否则 SSR 渲染后状态不同步 -
placeholder属性不能删:哪怕只是placeholder=" ",也要保留,否则 Safari 根本不进占位符渲染流程
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











