如何用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
相关产品推荐
相关产品推荐

