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

用纯CSS实现聚焦显示的下拉菜单 解决tab切换焦点菜单消失问题

问题描述

我正在为网站头部开发下拉菜单,目前已实现hover「Information For」文本时弹出菜单的效果。我还希望支持聚焦子菜单选项,但当前使用tab键遍历站点元素时,仅可聚焦顶部触发按钮,切换到下一个元素时菜单就会消失,请问基于我当前的代码结构是否可以实现该需求?

现有HTML代码

<div class="top-bar">
  <div class="info-for">
    <button>Information For&nbsp;&nbsp;&#9660;</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上即可:

  1. 删除.info-for button选择器下的&:hover + .dropdown, &:focus + .dropdown规则
  2. 给.info-for容器新增如下规则:
.info-for {
  // 原有其他规则全部保留
  &:hover .dropdown,
  &:focus-within .dropdown {
    display: block;
  }
}

修改后的逻辑可以完全覆盖你的需求:

  • 只要鼠标悬停在.info-for容器内的任意元素(触发按钮、下拉菜单本身),下拉就保持显示
  • 只要.info-for容器内有任意元素处于聚焦状态(触发按钮、下拉内的所有链接),下拉就保持显示
  • 当tab切出.info-for容器的所有元素后,下拉自动隐藏,符合无障碍访问要求

如果需要进一步优化体验,可以给下拉内的a标签补充focus状态的高亮样式,和hover状态保持一致即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 13:06:07