仅用 :placeholder-shown 无法可靠实现浮动标签动画,因其仅在 placeholder 可见时为 true,输入、聚焦或粘贴空格等即失效,导致标签“掉回原位”;必须组合 :focus 或 :not(:placeholder-shown) 等伪类,并确保 HTML 结构、placeholder 属性及紧邻兄弟关系正确。

:placeholder-shown 单独不能实现可靠浮动标签动画,必须和 :focus、:not(:placeholder-shown) 或 :valid 组合使用,且 HTML 结构、属性缺一不可。
为什么只写 :placeholder-shown 标签会“掉回原位”
这个伪类只在 input 有 placeholder 属性且内容为空(不含可见字符、空格、换行等)时为 true。用户一输入、一聚焦、甚至粘贴一个全角空格,:placeholder-shown 就立刻变成 false —— 标签失去匹配规则,CSS 回退到默认样式,视觉上就是“啪一下掉回去”。
- 它不感知“有没有值”,只感知“placeholder 是否正在显示”
-
value=" "(半角空格)、value=" "(全角空格)、value="\n"都会让它失效,但业务上这些仍是“空” -
type="number"输入字母后 value 被清空,:placeholder-shown意外触发,导致标签错误上浮
input:not(:placeholder-shown) + label 是保持上浮的关键
这是纯 CSS 方案里最稳定的状态判断:只要 placeholder 不再显示,就认为输入框“已介入”,标签应保持上浮。它比 :valid 更宽松,不依赖 required 或校验规则,也不受 "0"、" " 等值干扰。
- 必须确保
input带placeholder属性(哪怕写成placeholder=" ") -
label必须是input的**紧邻兄弟元素**,用+才能生效 - 要预留上浮空间:
input得设padding-top,否则文字会被上浮的label遮住 -
label必须加pointer-events: none,否则点不到输入框
三种状态怎么用 CSS 同时覆盖
浮动标签真正需要响应的是三个独立状态:空且未聚焦、空但已聚焦、非空(无论是否聚焦)。靠一个伪类做不到,得叠加写:
立即学习“前端免费学习笔记(深入)”;
-
input:placeholder-shown + label→ 初始态:标签在框内,默认位置、小字号、浅色 -
input:focus + label→ 聚焦态:标签上浮,同时给焦点反馈(如边框变色) -
input:not(:placeholder-shown) + label→ 已输入态:标签保持上浮,不因失焦而回落
注意顺序::placeholder-shown 规则要放在最后,否则会被前面更宽泛的选择器覆盖。
不加 required 时别硬套 :valid
如果字段可选,又没加 required,:valid 在空值时也返回 true(因为“空”本身不违反任何校验),标签永远上浮不下去——这完全违背设计意图。
- 想用
:valid,就必须配required,或加pattern/type="email"等约束 -
type="number"下输入"0"会触发:valid,但业务可能要求“非零”,这时 UI 和逻辑错位 - 边界字符(零宽空格、BOM、emoji)会让
:valid和:placeholder-shown同时失效,纯 CSS 无解
复杂表单里,:not(:placeholder-shown) 是更务实的选择;真要 100% 可靠,JavaScript 监听 input 和 blur 并切换 class 仍是兜底方案。


















