:placeholder-shown 在 <input> 或 <textarea> 有 placeholder 属性且内容为空(含纯空白)时触发;输入空格或回车即失效,type="number" 输入非法值时可能意外触发。

什么是 :placeholder-shown 的实际触发条件?
这个伪类只在 <input> 或 <textarea> 元素有 placeholder 属性,且当前内容为空(包括只含空白字符)时才匹配。它不是“占位符可见就生效”,而是“输入框空着且 placeholder 正在显示”——所以一旦用户输入一个空格或回车,:placeholder-shown 就立刻失效。
- 必须写
placeholder="...",否则伪类不激活 -
value=""或value=" "都算空,但value=" "(全角空格)也生效,因为浏览器仍视其为“无实质内容” -
<input type="number">在输入非法值(如字母)时会清空 value,此时可能意外触发:placeholder-shown,需留意
浮动标签的 DOM 结构怎么搭才可靠?
不能把标签(label)放在 input 外面再靠绝对定位“盖上去”——那样会导致焦点/可访问性问题。推荐结构:
<div class="field"> <input type="text" placeholder="姓名" id="name"> <label for="name">姓名</label> </div>
-
label必须用for关联id,确保点击标签能聚焦输入框 -
label放在input后面,才能用+ label或~ label选择器控制样式 - 不要用
float或display: inline-block破坏流式布局,统一用position: relative / absolute配合transform
如何用 :placeholder-shown 控制标签位置?
核心逻辑:默认让 label 浮在输入框上方;当输入框非空(即 :placeholder-shown 不匹配)时,把它“压”回原位或缩小字体。
.field {
position: relative;
}
.field label {
position: absolute;
top: 0;
left: 0;
font-size: 14px;
transform: translateY(-50%) translateX(8px);
transition: all 0.2s ease;
pointer-events: none;
}
.field input:not(:placeholder-shown) + label,
.field input:focus + label {
font-size: 12px;
transform: translateY(-16px) translateX(8px);
}-
input:not(:placeholder-shown) + label覆盖“已输入”状态 -
input:focus + label确保刚点击空框时标签也上浮(否则首次聚焦没 placeholder,:placeholder-shown不生效,标签卡在下面) - 不要只依赖
:placeholder-shown,它对初始空值无效(比如页面加载后用户还没碰输入框,但 placeholder 已显示)
为什么有时标签“闪一下”或定位偏移?
常见原因集中在两个地方:
立即学习“前端免费学习笔记(深入)”;
-
label默认是行内元素,若父容器有line-height或font-size继承干扰,transform基准会漂移 → 统一给label加display: block和明确font-size -
transition写在label上,但input的:focus和:not(:placeholder-shown)可能不同步触发 → 把过渡效果统一写在label的基础样式里,别拆到多个状态中 - iOS Safari 对
:placeholder-shown支持较晚(iOS 12+),旧版本会直接跳过规则 → 如果需兼容,得 fallback 到 JS 监听input和blur
浮动标签看着简单,真正稳定的关键不在动画,而在对空值状态的精确感知和对 focus/placeholder 显示时机的交叉覆盖。漏掉 input:focus + label 这条规则,用户第一次点进去就会觉得“标签没动”。


















