仅使用 CSS 创建折叠导航

2025-05-24

仅使用 CSS 创建折叠导航

虽然使用 JavaScript 打开移动导航是一个不错的选择,但仅使用 CSS 也可以实现。即使是子菜单也不一定需要任何 JS 才能工作,伪类兄弟选择器就是答案!

如何

折叠导航通常由被亲切地称为“汉堡菜单”的图标触发,该图标指的是三条水平线。这是一个备受争议的图标,但人们已经习惯了它,所以现在我们先坚持使用它。

打开和关闭折叠导航

要创建纯 CSS 导航,我们需要使用<input />带有 的元素type="checkbox",并使用:checked伪类 来判断它是否被选中。此外,我们还需要一个<label>,并通过属性链接到 input 元素for
这是我通常创建的简化版本,为了清晰起见,我使用元素而不是类来设置样式:

<nav>
  <input type="checkbox" id="trigger" />
  <label aria-label="open main navigation" for="trigger"><span></span></label>
  <ul>
    <li>
      <a href="#">Link</a>
    </li>
    <li>
      <a href="#">Link</a>
    </li>
    <li>
      <a href="#">Link</a>
    </li>
  </ul>
</nav>
Enter fullscreen mode Exit fullscreen mode

请注意,我将标签元素放在输入元素之后,这样就可以通过输入的状态(:focus:checked等)来设置标签的样式。

隐藏复选框

复选框输入框需要完全消失。我添加了位置固定,因为导航的其余部分是固定的,点击复选框标签的标准行为是滚动到它,这意味着滚动到顶部。

input {
  opacity: 0;
  width: 0;
  height: 0;
  appearance: none;
  position: fixed;
}
Enter fullscreen mode Exit fullscreen mode

创建触发器

您可以在此处添加汉堡图标的背景图片,也可以使用 before 和 after 选择器来创建它们。这是触发器的可见部分,它将代表“导航已关闭!”状态。

您可能对标签span内的“不必要”感到疑惑label,我添加它是为了使其样式更容易,您可以将跨度省略。

label {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  width: 15px;
  height: 10px;
  margin: 40px;
}

label span {
  display: block;
  width: 100%;
  background: hotpink;
  height: 2px;
  transition: transform 1s;
}

label span::before,
label span::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  display: block;
  height: 2px;
  background: hotpink;
  transition: 0.4s
}

label span::before {
  top: 0;
}

label span::after {
  top: calc(100% - 2px); /* to make the transition easier :) */
}
Enter fullscreen mode Exit fullscreen mode

隐藏导航

虽然你可以直接display: none在这里添加,然后display: block在需要显示时使用变换会更有趣。
我选择ul在 X 轴上平移 100vw,让它在屏幕上隐藏,直到用户点击触发器。

ul {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  transform: translateX(100vw);
  transition: transform 0.2s;
  background: white;
}
Enter fullscreen mode Exit fullscreen mode

创造“开放状态”

我之前谈到过使用 :checked 伪类,伪类是在元素具有某种状态时添加到元素的关键字。

单选按钮和复选框输入类型都有:checked状态。复选框可以通过点击来选中或取消选中,而要选中另一个单选按钮则需要另一个按钮。复选框更符合我们的目标,所以我们使用它们。

这是为导航触发器的打开状态添加 CSS 的地方,很多网站都没有对此进行样式和动画处理,在我看来这是一种遗憾。

如果您是 CSS 新手,这段代码可能看起来比较难懂,但如果您大声朗读出来,有时能帮助您更清楚地理解。例如,第一行:选择已选中的“input”的同级“label”的内部元素“span”。
好吧,这听起来还是有点乱,但熟能生巧。

input:checked + label span {
  transform: rotate(45deg);
}

input:checked + label span::before, input:checked + label span::after {
  top: calc(50% - 1px);
  transition: 0.4s;
}
input:checked + label span::after {
  transform: rotate(90deg);
}
Enter fullscreen mode Exit fullscreen mode

显示导航

我在这里使用了通用同级选择器,这意味着“选择任何已检查输入的同级 ul”,input:checked + label + ul也可以起作用,但对错误更敏感(如果在其间添加一个元素会怎样?)。

input:checked ~ ul {
  transform: none;
  transition: transform 0.4s; 
}

Enter fullscreen mode Exit fullscreen mode

带有贝塞尔曲线和所有精美内容的漂亮 SCSS 版本:

但为什么?

因为我们可以!

这看起来比仅仅用 JavaScript 添加一个类要复杂得多,你可能是对的。如果你想更好地处理伪类和兄弟选择器,这不仅是一个很好的练习,而且它非常坚固。想象一下,你的网站在 JS 中出现了一个小错误,这意味着人们将无法再使用你的导航。让我们把那些疯狂的动画留给 JavaScript,把像打开和关闭导航这样的简单操作保留为 CSS 代码。

可访问性

抛弃整篇文章的一个好观点是,使用输入元素来打开和关闭导航是不符合语义的

但如果你认真想想,大多数使用屏幕阅读器的人(可能会注意到你使用了一个input元素而不是一个更具语义的button元素的群体)并不是真正的开发人员,但你可能会惹恼盲人开发人员,要小心。

触发器可以通过键盘自动访问,如果您还添加一个清晰的触发器,那么aria-label您所做的就比大多数使用button打开折叠导航的开发人员做得更多。

我真的很想听听盲人用户或无障碍专家的意见,如果我真的一无所知,请在评论中告诉我。

文章来源:https://dev.to/cydstumpel/creating-a-fold-out-navigation-with-css-only-4g9k
PREV
我的 2024 年优质链接列表
NEXT
今年我在 Web 开发中学到的 5 件事