:placeholder-shown 无法单独实现浮动标签,因其仅在 input 有 placeholder 且内容完全为空时匹配,不响应聚焦、校验状态,兼容性差(ie 不支持、safari ≤15.4 偶发失效),且依赖严格相邻的 input + label 结构;必须配合三行基础 css(position: relative、pointer-events: none、transition)及状态组合规则,并需 js fallback 覆盖所有交互状态。

为什么:placeholder-shown不能单独实现浮动标签
它只在 input 有 placeholder 属性且内容**完全为空(不含空格、全角空格、零宽字符)**时匹配。用户一点击、一输入、甚至粘贴个 ,它就立刻失效——而浮动标签必须覆盖“空但已聚焦”“非空且失焦”这两种状态,:placeholder-shown 一个都管不了。
它不响应 :focus,也不感知校验结果;IE 完全不支持,Safari ≤15.4 偶发失效;没写 placeholder 属性(哪怕值是空字符串),它永远为 false。
input + label 结构必须严格相邻,否则规则不生效
所有依赖 + 的选择器(比如 input:focus + label)都要求 label 紧跟在 input 后面,中间不能插任何元素:
- ✅ 正确:
<input placeholder="邮箱"><label>邮箱</label> - ❌ 错误:
<label>邮箱</label><input placeholder="邮箱">(+只选后继) - ❌ 错误:
<input><span class="icon"></span><label>邮箱</label>(中间有span,+断链)
若需插入图标或错误提示,得用 ~(通用兄弟选择器)+ 包裹容器,但会牺牲部分精确性。
必须写的三行基础 CSS 才能动起来
漏掉任意一行,标签要么飘出屏幕,要么点不动,要么动画卡顿:
-
label { position: relative; }—— 不加这句,transform: translateY()基准是视口,不是输入框 -
label { pointer-events: none; }—— 不加这句,label会挡住input点击区域 -
label { transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); }—— 不加动画,上浮是瞬移,不是“浮动”
典型组合规则示例:
input:placeholder-shown + label {
opacity: 0;
transform: translateY(1em);
}
input:not(:placeholder-shown) + label,
input:focus + label {
position: absolute;
top: -0.8em;
left: 8px;
font-size: 0.8em;
background: white;
padding: 0 4px;
opacity: 1;
transform: none;
}
兼容性兜底::not(:placeholder-shown) 不等于 :valid
:not(:placeholder-shown) 表示“占位符已消失”,但不保证输入合法;:valid 需要 required 或其他校验属性才生效。两者行为不同:
- 用户输入空格 →
:not(:placeholder-shown)为true,:valid仍为false - 没加
required→:valid永远不会触发,只能靠:not(:placeholder-shown) - Safari 旧版对
:placeholder-shown支持不稳定,建议 JS 监听input和blur事件手动 toggle 类名作为 fallback
真正难的不是写出那几行 CSS,而是把“空+聚焦”“非空+失焦”“非空+聚焦”三种状态全部覆盖,漏一种,UI 就卡在奇怪位置。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











