CSS :has() 选择器实现跨兄弟容器的焦点联动样式

本文详解如何利用 css `:has()` 选择器,在存在中间包裹容器(如 `

`)的情况下,精准匹配并响应目标元素(如 ``)的聚焦状态,从而动态样式化其前序兄弟组件中的嵌套标签(如 `` 内的 `.k-label`)。

当 HTML 结构中 被嵌套在 中,而 与其同级但不直接相邻时(即结构为 kendo-label → div → kendo-textbox),无法再使用 +(相邻兄弟)组合器。此时必须改用 :has() 的后代关系表达能力:将整个路径写入单个 :has() 函数内,使其语义变为“选择后面紧邻的 div,且该 div 内部包含处于 :focus-within 状态的 .k-input-solid 元素”。

✅ 正确写法如下:

kendo-label:has(+ div .k-input-solid:focus-within) .k-label {
  color: var(--blue-05);
  font-weight: 600;
}

⚠️ 关键说明:

  • + div 表示「下一个相邻兄弟元素是 」;
  • div .k-input-solid:focus-within 是其内部的后代选择器,表示该 内任意层级下存在获得焦点或其子元素获得焦点的 .k-input-solid(推荐用 :focus-within,兼容输入框内含 等子控件的场景);
  • 整个 :has(+ div .k-input-solid:focus-within) 必须写在一个 :has() 中——不可拆分为多个 :has() 链式调用(如 :has(+ div):has(+ .k-input-solid)),因为后者仍要求两个条件分别作用于同一级后续兄弟,逻辑上不成立。
  • ? 实际 HTML 示例验证:

    
      
    
    
      
    

    只要用户点击或 Tab 进入该 (或其内部原生 ),.k-label 即实时高亮为蓝色加粗。

    ? 补充建议:

    • 若组件库实际渲染出的是 而非自定义元素,可微调为 :has(+ div input.k-input-solid:focus) 提升兼容性;
    • 目前 :has() 已获 Chrome 105+、Firefox 121+、Safari 15.4+ 原生支持,生产环境使用前建议通过 caniuse.com/:has 检查目标浏览器覆盖率;
    • 不要尝试用 :focus 替代 :focus-within —— 后者能正确响应 内部 聚焦,而前者仅匹配元素自身聚焦(对 Web Component 封装的组件通常无效)。

    此方案无需 JavaScript、不侵入组件内部结构,纯 CSS 实现语义清晰、性能高效,是现代前端样式化跨容器交互的理想实践。