:focus-within 是唯一能跨层级感知子元素焦点的伪类,需将 input 和 label 置于同一父容器内并设为同级子元素,配合 opacity 过渡实现聚焦隐藏;IE11 不支持,须降级为 JS 控制。

纯 CSS 就能实现输入框聚焦时隐藏关联的 label,但必须用 :focus-within 包裹父容器,不能只靠 input:focus + label —— 后者只能控制紧邻后置的 label,且无法处理嵌套结构。
为什么 input:focus + label 大概率失效
这个选择器要求 label 必须紧跟在 input 后面、同级、中间不能隔任何标签。实际项目中(比如 Vuetify、Element Plus),input 往往深埋在多层 div 里,label 又常放在容器顶部或外部,DOM 结构根本不满足“紧邻兄弟”条件。一旦中间插了 div 或 span,+ 就完全失联。
-
input:focus + label只匹配直接后继,input:focus ~ label能匹配后续所有同级label,但依然要求它们在同一个父容器下 - 如果
label和input不在同一个父元素内(例如label在表单顶部,input在底部),CSS 无解,必须换 JS -
:focus-within是唯一能跨层级“感知”子元素焦点的伪类,兼容性到 Chrome 67+/Firefox 61+,IE 完全不支持
:focus-within 的正确写法与结构约束
核心是把 input 和目标 label 放进一个共同父容器,然后对该容器用 :focus-within,再通过 ~ 或 + 选中其内部的 label。例如:
<div class="field"> <label>用户名</label> <input type="text"> </div>
CSS 写成:
.field label {
opacity: 1;
transition: opacity 0.15s ease;
}
.field:focus-within label {
opacity: 0;
}
- 父容器
.field必须包裹label和input,且两者为同级子元素 -
transition必须写在默认状态(即.field label),不是只写在:focus-within下 - 别用
display: none隐藏 —— 它不可动画,会导致突兀消失;opacity或visibility才可过渡
聚焦时 label 消失但 placeholder 还在?同步处理
label 隐藏了,但 input 的 ::placeholder 还显示着,视觉上容易混乱。可以用 input:focus::placeholder 一并隐藏:
.field input:focus::placeholder {
color: transparent;
/* Safari 兼容: */
opacity: 0;
}
- 不要试图用
label的状态去控制::placeholder—— CSS 选择器无法从label影响input的伪元素 -
color: transparent在部分旧版 Safari 上不生效,补一句opacity: 0更稳 - 如果用了
required,还可加input:not(:placeholder-shown) + label保持 label 上浮,但这是另一套逻辑,和本题“聚焦即隐藏”冲突,别混用
IE11 或需要降级时的替代方案
如果必须兼容 IE11,:focus-within 无效,只能退回到 JS 监听 focus/blur 并切换类名:
<div class="field"> <label class="js-label">用户名</label> <input type="text" class="js-input"> </div>
CSS:
.field .js-label { transition: opacity 0.15s; }
.field.has-focus .js-label { opacity: 0; }
JS:
const input = document.querySelector('.js-input');
const field = input.closest('.field');
input.addEventListener('focus', () => field.classList.add('has-focus'));
input.addEventListener('blur', () => field.classList.remove('has-focus'));
注意:这里没用 input 自身加类,是因为某些 UI 框架(如 Ant Design)会拦截原生 focus 事件,导致监听失败;用 closest 找父容器更可靠。
真正难的不是写那几行 CSS,而是确认 DOM 结构是否允许你用 :focus-within —— 如果 label 和 input 分属不同组件、不同 Vue/React 片段,或者被框架动态挂载到不同位置,那 CSS 就彻底无能为力,得老老实实交由 JS 控制显隐。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











