只用 :focus 会失效,是因为它仅响应焦点状态,不感知内容是否已输入;要实现“输入后标签上浮”,必须配合 :not(:placeholder-shown),且需 input 有非空 placeholder 属性并获浏览器支持。

为什么只用 :focus 会失效
很多开发者一上来就写 input:focus + label { transform: translateY(-20px); },结果用户输完内容点别处,label 立刻掉回框里盖住文字。这不是 bug,是预期行为——:focus 只管焦点,不管内容是否已填。真正要响应「已输入」状态,必须靠 :not(:placeholder-shown)。
这个伪类生效有两个硬条件:
-
input或textarea必须有placeholder属性,且值不能是空字符串(哪怕写placeholder=" "都行) - 浏览器必须支持
:placeholder-shown(IE 全系不支持,Edge 16+、Chrome 47+、Firefox 51+ 均支持)
form-floating 在 Bootstrap 5 中的隐藏约束
Bootstrap 5 的 form-floating 类看似开箱即用,但结构错一点就全乱:
-
<label></label>必须**紧挨着**<input>后面,中间不能插其他元素(包括注释、空格、换行符都可能破坏选择器匹配) -
<input>的placeholder值不能为"";设成placeholder=" "或placeholder=" "才能触发:not(:placeholder-shown) -
<select></select>要用<option disabled selected>请选择</option>模拟 placeholder,否则伪类不生效 - 自定义高度或圆角后,
.form-label的transform偏移量往往需要手动重调,否则上浮位置偏高或偏低
纯 CSS 实现时必加的三处 transition
浮动动画卡顿、突兀、闪一下,大概率是 transition 没配对:
-
label的transform和font-size必须加transition,否则上浮生硬 -
input的border-color也要加transition,否则聚焦时边框变色“啪”一下跳过去 -
label的opacity建议从0.6→1渐变,避免字体在浅背景上突然变黑“闪一下” - 千万别写
transition: all .2s——它会让width、height这些没动的属性也参与过渡,引发渲染抖动
JS 动态填充后标签不上浮怎么办
编辑页回填数据时,常见现象:输入框已显示值,但 label 还赖在框里不动。这是因为 :placeholder-shown 是基于 DOM 状态判断的,JS 直接赋值 input.value = "xxx" 不会自动清除 placeholder 或触发状态更新。
必须手动补两步:
- 设置
input.value后,立即调用input.dispatchEvent(new Event('input', { bubbles: true })) - 如果用了
required或校验逻辑,还需同步调用input.reportValidity()防止样式被 invalid 状态干扰 - 注意:不要用
change事件代替input,它只在失焦时触发,无法满足实时浮动需求
最易被忽略的其实是定位上下文——多个 input 共用一个父容器时,若没给每个 input 的直接包装 <div> 加 <code>position: relative,所有 label 都会相对同一祖先定位,叠在一起谁也看不见。











