用纯CSS实现聚焦显示的下拉菜单 解决tab切换焦点菜单消失问题
问题描述
我正在为网站头部开发下拉菜单,目前已实现hover「Information For」文本时弹出菜单的效果。我还希望支持聚焦子菜单选项,但当前使用tab键遍历站点元素时,仅可聚焦顶部触发按钮,切换到下一个元素时菜单就会消失,请问基于我当前的代码结构是否可以实现该需求?
现有HTML代码
<div class="top-bar"> <div class="info-for"> <button>Information For ▼</button> <div class="dropdown"> <ul> <li><a href="#">Info For Option 1</a></li> <li><a href="#">Info For Option 2</a></li> <li><a href="#">Info For Option 3</a></li> <li><a href="#">Info For Option 4</a></li> <li><a href="#">Info For Option 5</a></li> </ul> </div> </div> <div class="give-search"> <a href="#">Give</a> <span class="spacer">|</span> <button>Q</button> </div> </div>
现有CSS(SCSS语法)代码
//-----BASE-----// :root { --purple: #61578b; --gold: #deb364; --white: #fefefe; --background-gray: #f2f2f2; --border-gray: #cccccc; --font-serif: "Noto Serif", serif; --font-sans: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; } body { font-family: var(--font-sans); margin: 0; } a { text-decoration: none; &:focus { outline: none; } } //-----HELPER-----// .dropdown { display: none; position: absolute; top: 100%; background: var(--white); border: 1px solid var(--border-gray); & ul { list-style-type: none; padding: 0; margin: 0; width: max-content; } & a { display: block; } &:hover, &:focus-within { display: block; } } //-----HEADER-----// .top-bar { background-color: var(--purple); color: var(--white); font-weight: bold; position: relative; & > * { display: inline-block; } & .dropdown { & li:hover, & li:focus-within { background-color: var(--background-gray); } & a { padding: 0.75rem 0.5rem; color: var(--purple); font-family: var(--font-sans); font-weight: bold; } } } .info-for { font-family: var(--font-serif); & button { all: unset; cursor: pointer; padding: 1rem; &:hover, &:focus { color: var(--gold); } &:hover + .dropdown, &:focus + .dropdown { display: block; } } } .give-search { float: right; padding: 1rem; & a { color: var(--white); &:hover, &:focus { color: var(--gold); } } & .spacer { padding: 0 2rem; } & button { all: unset; cursor: pointer; &:hover, &:focus { color: var(--gold); } } }
解决方案
你当前的代码结构完全可以实现该需求,问题出在下拉菜单的显示触发逻辑上:
当前你仅给触发按钮的hover和focus状态绑定了相邻选择器来控制下拉显示,当你按下tab离开按钮、聚焦到下拉内的链接时,按钮会先失去focus状态,相邻选择器的规则失效,下拉会先变为display: none,此时你给dropdown设置的:focus-within规则无法触发。
只需要调整触发规则,将下拉显示的判定绑定到父容器.info-for上即可:
- 删除
.info-for button选择器下的&:hover + .dropdown, &:focus + .dropdown规则 - 给
.info-for容器新增如下规则:
.info-for { // 原有其他规则全部保留 &:hover .dropdown, &:focus-within .dropdown { display: block; } }
修改后的逻辑可以完全覆盖你的需求:
- 只要鼠标悬停在
.info-for容器内的任意元素(触发按钮、下拉菜单本身),下拉就保持显示 - 只要
.info-for容器内有任意元素处于聚焦状态(触发按钮、下拉内的所有链接),下拉就保持显示 - 当tab切出
.info-for容器的所有元素后,下拉自动隐藏,符合无障碍访问要求
如果需要进一步优化体验,可以给下拉内的a标签补充focus状态的高亮样式,和hover状态保持一致即可。
内容的提问来源于stack exchange,提问作者skinner
相关产品推荐
相关产品推荐

