
本文详解如何利用单个 `:has()` 伪类组合选择器,跨越 dom 层级(如跳过中间 `
当 Kendo UI 组件自动插入 <div> 容器导致 HTML 结构变为:
<kendo-label> <label class="k-label">用户名</label> </kendo-label> <div> <kendo-textbox class="k-input-solid"></kendo-textbox> </div>
原先适用于相邻兄弟关系的 kendo-label:has(+ .k-input-solid:focus-within) 将失效——因为 <kendo-textbox> 不再是 <kendo-label> 的直接相邻兄弟,而是嵌套在 <div> 内的后代元素。
关键误区在于尝试链式调用 :has()(如 :has(+ div):has(+ .k-input-solid:focus-within)),这在 CSS 中不合法:每个 :has() 只能接受一个选择器列表,且必须作为一个整体进行匹配判断。
✅ 正确解法是将层级关系写入同一个 :has() 内部,利用空格组合符表达“后代”关系:
立即学习“前端免费学习笔记(深入)”;
kendo-label:has(+ div .k-input-solid:focus-within) .k-label {
color: var(--blue-05);
font-weight: 600;
}该选择器含义为:
→ 查找 <kendo-label> 元素;
→ 它的紧邻下一个兄弟元素是 <div>;
→ 且该 <div> 内部任意深度包含一个拥有 class="k-input-solid" 并处于 :focus-within 状态的元素(即 <kendo-textbox> 获得焦点或其内部可聚焦子元素获得焦点);
→ 若满足,则选中该 <kendo-label> 下的 .k-label 子元素并应用样式。
? 提示:
- 使用 :focus-within 比 :focus 更健壮,它能捕获 <kendo-textbox> 自身聚焦,也兼容其 Shadow DOM 内部输入框的聚焦行为(Kendo 组件常采用此结构);
- 若需严格限定仅 <kendo-textbox> 自身聚焦(非其子元素),可替换为 :focus,但需确保组件实际渲染的 <input> 或 <textarea> 能正确触发该状态;
- 当前方案兼容 Chrome 105+、Edge 105+、Safari 15.4+,Firefox 已支持(v123+),生产环境建议配合 @supports 特性检测做渐进增强。
完整验证示例:
<style>
kendo-label:has(+ div .k-input-solid:focus-within) .k-label {
color: #0066cc;
font-weight: 600;
transition: color 0.2s;
}
</style>
<kendo-label>
<label class="k-label">邮箱地址</label>
</kendo-label>
<div>
<kendo-textbox class="k-input-solid"></kendo-textbox>
</div>✅ 点击 textbox 后,上方 label 即实时变色加粗。
⚠️ 注意::has() 不支持在 @keyframes 或其他伪类中嵌套使用,且无法通过 JavaScript 的 querySelector() 调用(仅 CSS 引擎解析)。
总结:面对不可控的 DOM 插入(如第三方组件包裹 <div>),应优先用单 :has(关系选择器) 表达跨层级条件,而非拆分多个 :has()——这是语义正确性与浏览器兼容性的双重保障。










