单独使用:placeholder-shown无法实现完整浮动标签效果,因其仅在占位符显示时生效,用户输入后即失效,无法维持“有值但失焦”状态;必须组合:focus、:valid(需required)或JavaScript监听input/blur事件来补全状态逻辑。

:placeholder-shown 本身不能直接实现浮动标签(floating label),它只是检测 input 是否处于 placeholder 显示状态——而这个状态在用户输入后就消失了,无法覆盖「有值但失去焦点」的场景。真正能撑起浮动标签逻辑的是 :placeholder-shown + :focus + :valid 的组合,且必须配合 required 属性或 JavaScript 补位。
为什么单独用 :placeholder-shown 会失效?
用户输入后,:placeholder-shown 立即为 false,标签立刻“掉回”原位;失去焦点时也无法保持上浮状态。常见错误是只写:
input:placeholder-shown + label { transform: translateY(0); }
input:not(:placeholder-shown) + label { transform: translateY(-20px); }
这会导致:输入文字 → 标签上浮;删光文字 → 标签掉回;但光标点进去再点出来(没删内容)→ 标签又掉回,体验断裂。
纯 CSS 方案:必须加 required + :valid
利用表单验证伪类,在有值时维持上浮状态。前提是 input 必须带 required 属性(否则 :valid 永远为 true):
立即学习“前端免费学习笔记(深入)”;
-
input:placeholder-shown + label:初始状态,标签在默认位置 -
input:focus + label, input:valid + label:聚焦时或有值时,标签上浮 - label 需设
position: absolute,并用transform: translateY()或top控制位移 - input 需设
padding-top预留标签上浮后的空间,避免文字被遮挡
示例关键片段:
input { padding-top: 1.5rem; }
label { position: absolute; top: 0.75rem; transition: transform 0.2s ease; }
input:placeholder-shown + label,
input:not(:placeholder-shown):not(:valid) + label {
transform: translateY(0);
}
input:focus + label,
input:valid + label {
transform: translateY(-1rem);
}
不加 required 怎么办?只能靠 JS 补位
如果业务不允许加 required(比如可选字段),CSS 就无解::placeholder-shown 和 :valid 都不可靠。此时必须监听 input 和 blur 事件,动态切换 class:
- 监听
input事件:值非空时加has-value - 监听
blur事件:值为空时移除has-value,否则保留 - CSS 改用
.has-value + label替代:valid - 注意:要处理粘贴、剪切、清空按钮等边界行为,建议用
requestAnimationFrame延迟读取 value
兼容性与真实陷阱
:placeholder-shown 在 Safari 9+、Chrome 47+、Firefox 51+ 支持,但 IE 完全不支持;Edge 16+ 才开始支持。更隐蔽的问题是:
- 某些安卓 WebView(尤其旧版)对
:placeholder-shown触发时机不一致,输入法提交延迟可能导致状态错乱 -
input[type="number"]在 Chrome 中即使为空也常不触发:placeholder-shown(因 type 导致 placeholder 不显示) - label 用
transform上浮时,若父容器有overflow: hidden,可能被裁剪——得给父容器加overflow: visible或改用top+position
浮动标签看着简单,但真要跨浏览器稳住,:placeholder-shown 只是起点,不是终点。


















