使

使用纯 CSS 制作的折叠标签页

2025-06-04

使用纯 CSS 制作的折叠标签页

是的,这又一篇关于纯 CSS 有多棒,以及如何不用一行 JavaScript 就能做出酷炫作品的“文章”。我为什么要费心写它?因为我仍然着迷于纯 CSS 有多棒,以及如何不用一行 JavaScript 就能做出酷炫作品。

在我们开始之前,您可以在这里找到代码的演示,以及代码本身。欢迎随意探索和体验!

最后的小免责声明:这一切只是为了好玩,并向您展示 CSS 有多么神奇。

HTML结构

我们将使用非常简单的 HTML 标记来定义我们的手风琴标签:

  • .tabs-container— 包装元素来承载所有与标签相关的元素;
  • input.tab-actor— 隐藏单选按钮来控制标签内容的可见性;
  • label.tab-button— 链接到输入的标签,用作标签按钮;
  • .tab-content— 包装您认为值得放入的任何内容;

最小的例子如下:

<div class="tab-container">
  <input type="radio" id="tab-1" name="tabs" class="tab-actor" checked />
  <label for="tab-1" class="tab-button">Lorem ipsum</label>
  <section class="tab-content">
    <div class="content"></div>
  </section>
</div>
Enter fullscreen mode Exit fullscreen mode

工作原理

主要思路是利用 HTML 表单控件简单却强大的功能,通过 CSS 伪类来获取状态并访问状态。也就是说,我:checked在这里使用了伪类。这意味着我使用组合器来设置已检查输入框的相邻兄弟元素的样式+

为了模拟标签页的行为,我需要只显示活动标签页的内容。所谓活动标签页,指的是最靠近已勾选单选按钮的内容。

单选按钮也应该隐藏,只留下链接的标签可见且可交互。

长话短说,这些标签页的工作原理就是这样的。让我们为这些标签页编写一些基本的 CSS 代码。

一些基本代码

:root {
  --tab-button-order: 1;
  --tab-content-order: 10;
}

.tab-container {
  display: flex;
  flex-wrap: wrap;
}

.tab-actor {
  display: none;
}

.tab-button {
  order: var(--tab-button-order);
}

.tab-content {
  order: var(--tab-content-order);
  display: none;
}

.tab-actor:checked + .tab-button + .tab-content {
  display: block;
}
Enter fullscreen mode Exit fullscreen mode

让我们仔细研究每条规则来了解发生了什么。

首先,我为 order 属性创建了一些 CSS 变量,这就是内部:root规则。我们稍后再讨论这个问题。

.tab-container {
  display: flex;
  flex-wrap: wrap;
}
Enter fullscreen mode Exit fullscreen mode

我们采用了弹性布局。它允许我们使用任意数量的标签页,因为它会自动分配其子元素。否则,我们需要手动设置固定宽度的值。

默认情况下,所有弹性项目都挤在一行中,但我们需要将 Tab 按钮放在顶部,将内容放在底部。使用flex-wrap: wrap弹性布局可以将较大的元素放在下一行。

<input type="radio" id="tab-1" name="tabs" class="tab-actor" checked />
<label for="tab-1" class="tab-button">Lorem ipsum</label>
Enter fullscreen mode Exit fullscreen mode

我们使用输入的属性和标签的属性将标签链接到输入id。当输入-标签对的属性值相同时,点击标签会像直接点击输入一样激活输入。

这使我们能够隐藏输入:

.tab-actor {
  display: none;
}
Enter fullscreen mode Exit fullscreen mode

接下来,我们添加一些黑色弹性魔法来获得我们想要的布局。

HTML中我们已经写出了这样的结果:

[tab]
[content]
[tab]
Enter fullscreen mode Exit fullscreen mode

但我们需要的是:

[tab][tab]
[content]
Enter fullscreen mode Exit fullscreen mode

为了实现我们的目标,我们应该使用一个orderCSS 属性,无论元素在 DOM 树中的实际位置如何,它都会对 flex 布局中的元素进行排序(这里没有双关语的意思)。以下代码设置了元素的顺序,使其.tab-button位于布局的开头和.tab-content末尾:

.tab-button {
  order: var(--tab-button-order);
}

.tab-content {
  order: var(--tab-content-order);
  display: none;
}
Enter fullscreen mode Exit fullscreen mode

.tab-content默认情况下是隐藏的。我们使用以下代码取消隐藏活动选项卡的内容:

.tab-actor:checked + .tab-button + .tab-content {
  display: block;
}
Enter fullscreen mode Exit fullscreen mode

当然,这是一个很大的选择器,但它却能做到所有神奇的事情。所有内容都被隐藏,我们只想显示与激活的选项卡按钮对应的内容。这个选择器的字面含义如下:

显示选中输入后的按钮后的内容

+组合器选择紧邻的元素,这就是为什么 HTML 代码应该遵循这个精确的顺序。

另一种方法是使用~组合器。它也是相邻的,但不严格,会选择所有匹配的相邻元素。使用~组合器可以将选择器简化为:

.tab-actor:checked ~ .tab-content {
  display: block;
}
Enter fullscreen mode Exit fullscreen mode

不过在本例中,第一个选项卡会激活所有相邻的内容。为了避免这种情况,我们需要指定哪个选项卡显示哪些内容:

/* Don't write code like this. Please. */
.tab-actor.tab-1:checked ~ .tab-content.tab-1,
.tab-actor.tab-2:checked ~ .tab-content.tab-2,
.tab-actor.tab-3:checked ~ .tab-content.tab-3,
.tab-actor.tab-4:checked ~ .tab-content.tab-4 {
  display: block;
}
Enter fullscreen mode Exit fullscreen mode

说实话,优化并不多。

好的,现在我们有了用纯 CSS 和 HTML 制作的虽然不漂亮但可以工作的标签。

音乐时间!

或者更准确地说,是时候将标签页转换为手风琴了。
为什么?

在小屏幕上,标签并不是显示内容的最佳选择,而我们一开始试图避免的布局在这里却派上了用场:

Desktop:
[tab][tab]
[content]

Mobile:
[tab]
[tab]
[content]
Enter fullscreen mode Exit fullscreen mode

我们所需要的只是恢复弹性顺序并调整按钮宽度以适应小屏幕:

@media screen and (max-width: 480px) {
  .tab-button,
  .tab-content {
    order: initial;
  }

  .tab-button {
    width: 100%;
  }
}
Enter fullscreen mode Exit fullscreen mode

就是这样。成功了。

等等!还有更多!

一切都很酷很棒,就是这些标签太无聊了。让我们把它们打扮得漂漂亮亮吧!

* {
  margin: 0;
  padding: 0;
}

body {
  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
  max-width: 1280px;
  margin-inline: auto;
}

.tab-container {
  box-shadow: rgba(0, 0, 0, 0.5) 0 1px 2px;
  justify-content: center;
}

.tab-button {
  padding: 8px 16px;
  border-bottom: transparent 4px solid;
  transition: border-bottom-color 0.4s;
}

.content {
  padding: 16px;
}

.tab-actor:checked + .tab-button {
  border-bottom-color: rgb(82, 2, 136);
}
Enter fullscreen mode Exit fullscreen mode

我们添加了一些内边距、颜色和一些动画。现在看起来很棒!不过,正如你所注意到的,“移动”模式下的内容切换很慢,没有一点乐趣。接下来我们来添加一些亮点:

@media screen and (max-width: 480px) {
  .tab-button {
    border-bottom: 1px solid #ccc;
    transition: none;
  }

  .tab-content {
    background-color: ivory;
  }

  .tab-container.full-height {
    height: 100vh;
    flex-direction: column;
  }

  .tab-container.full-height .tab-content {
    display: block;
    height: auto;
    flex: 0;
    overflow: hidden;

    transition: 300ms flex;
  }

  .tab-container.full-height .tab-actor:checked + .tab-button + .tab-content {
    flex: 1;
  }
}
Enter fullscreen mode Exit fullscreen mode

这里发生了什么?我们添加了一个.full-height.tab-container,并在其上添加了一些有趣的 CSS。

.tab-container.full-height {
  height: 100vh;
  flex-direction: column;
}
Enter fullscreen mode Exit fullscreen mode

就在这里,我们告诉我们的手风琴占据整个屏幕的高度,并按列弹性布局排列所有子项。

.tab-container.full-height .tab-content {
  display: block;
  height: auto;
  flex: 0;
  overflow: hidden;

  transition: 300ms flex;
}

.tab-container.full-height .tab-actor:checked + .tab-button + .tab-content {
  flex: 1;
}
Enter fullscreen mode Exit fullscreen mode

现在我们对其施展魔法.tab-content,让它以漂亮的动画展开和收拢。

结语

我的朋友们,这就是我遇到的......啊,对不起,这就是我们如何制作响应式标签,无需一行 JS 即可动态切换到手风琴布局。


由@Ulyanka_A编辑

文章来源:https://dev.to/babichweb/accordion-tabs-with-pure-css-35ji
PREV
揭穿 DOM 的迷思:DOM 是与 HTML 一起发明的吗?
NEXT
表情符号让 Git 提交信息更美观