:placeholder-shown 仅检测 placeholder 存在且输入值严格为空,无法单独实现浮动标签;必须组合 :focus、:valid(需 required)或 JS 的 input/blur 事件才能覆盖所有交互状态。

:placeholder-shown 本身不能制作浮动标签,它只是个“空状态探测器”——只在 input 有 placeholder 属性且当前值为严格空字符串(不含空格、换行、全角空格)时返回 true。单靠它,标签既不会上浮,也无法保持上浮状态。
为什么只写 :placeholder-shown + + 会失效
常见错误是这样写:
input:placeholder-shown + label { transform: translateY(0); }
input:not(:placeholder-shown) + label { transform: translateY(-1rem); }
这会导致三种典型断裂:
- 用户点进去但没输内容 →
:placeholder-shown仍为true,标签不动,视觉无反馈 - 输入后删光 → 标签立刻掉回原位,不是“保留上浮”
- 光标点入已填字段(未删内容)→ 因
:placeholder-shown已失效且没:focus覆盖,标签瞬间掉落
必须组合 :focus 和 :valid(或 JS)补全状态
纯 CSS 可行路径只有一条:加 required 属性,用 :valid 捕获“有值”状态。否则 :not(:placeholder-shown) 在失焦时也失效(比如用户输完直接点别处)。
立即学习“前端免费学习笔记(深入)”;
-
input:placeholder-shown + label:初始空态,标签在框内 -
input:focus + label:聚焦即上浮,覆盖“空但已点入”场景 -
input:valid + label:有值即上浮,覆盖“非空失焦”场景(依赖required) - 三者共用
transition: transform 0.2s ease,避免瞬移
结构与样式最容易漏的硬性条件
以下任一缺失,整个链路就断:
-
label必须紧跟input后面,中间不能有注释、span、图标或换行符(+是紧邻兄弟选择器) -
input必须带placeholder属性,哪怕值为空格placeholder=" ";JS 动态设置在旧 Safari 中可能不触发 -
label必须设position: relative,否则transform: translateY()基准错乱,标签飘出视口 -
label需加pointer-events: none,否则会拦截input的点击 -
input要预留上浮空间,例如padding-top: 1.5rem,否则文字被遮挡
不加 required 就只能靠 JavaScript
业务不允许加 required(如可选字段)时,CSS 无解。必须监听两个事件:
-
input事件:值非空 → 加类has-value -
blur事件:值为空 → 移除has-value;否则保留 - CSS 改用
.has-value + label替代:valid,同时保留:focus + label
真正难的不是写对那几行 CSS,而是理解 :placeholder-shown 只是个信号源——它不感知焦点、不校验内容、也不维持状态。所有交互分支都得手动覆盖,漏掉任意一种,UI 就卡在奇怪的位置。


















