You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用CSS实现单个子菜单显示?解决:focus-within与:hover冲突

纯CSS实现导航子菜单单一显示的解决方案

问题场景

我正在开发导航组件,希望通过:focus-within状态将子菜单设为display:block以支持键盘导航。目前点击按钮后该状态生效,但hover兄弟元素时,原:focus-within状态的子菜单仍可见。需要实现:同一时间仅显示一个子菜单,要么自身处于:hover状态,要么自身处于:focus-within状态且无兄弟元素处于:hover状态。

给定代码

HTML结构

<ul>
  <li>
    <button>
    One
    </button>
    <span>
      submenu 1
    </span>
  </li>
  <li>
    <button>
      Two
    </button>
    <span>
      submenu 2
    </span>
  </li>
  <li>
    <button>
      Three
    </button>
    <span>
      submenu 3
    </span>
      
  </li>
</ul>

初始CSS

span {
  display: none;
}

li {
  &:hover > span {
    display: block;
  }
  
  &:focus-within > span {
    display: block;
  }
}

解决方案

可以通过CSS的:has()选择器实现需求,核心逻辑是:当父容器<ul>下存在被hover的<li>时,隐藏所有非hover且处于:focus-within状态的<li>的子菜单。

修改后的完整CSS:

span {
  display: none;
}

li {
  &:hover > span {
    display: block;
  }
  
  &:focus-within > span {
    display: block;
  }
}

/* 关键规则:当ul内有li被hover时,隐藏其他处于focus-within但未hover的li的子菜单 */
ul:has(li:hover) li:focus-within:not(:hover) > span {
  display: none;
}

规则解释

  • ul:has(li:hover):匹配包含任意被hover的<li>的<ul>容器
  • li:focus-within:not(:hover):匹配处于:focus-within状态但未被hover的<li>
  • 组合后,当有其他<li>被hover时,原本处于:focus-within的非hover<li>的子菜单会被隐藏,确保同一时间仅显示一个子菜单。

兼容性说明

:has()选择器目前已被Chrome、Firefox 121+、Safari等现代主流浏览器支持,纯CSS方案在现代环境下完全可行;若需兼容旧版浏览器,需结合JavaScript补充实现。

内容的提问来源于stack exchange,提问作者Himmel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 12:15:19