重新审视功能性 CSS 选项卡

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您的旅程的每个阶段提供云产品。立即开始使用 $200 免费信用额度!

“CSS 选项卡”的概念已经存在很长时间了。如果您在 Google 上搜索它,您会发现很多都是关于样式化的 CSS 选项卡,但关于构建真正功能性选项卡区域的内容却很少。至少,在功能性上,我们认为今天的选项卡区域是:点击一个选项卡,看到一个新的内容区域,而没有页面刷新。

解决功能性 CSS 选项卡的历史并不悠久。Brad Kemper 在 2008 年就开始尝试,试图利用:checked伪选择器和单选按钮以及相邻同级组合器。这是一种非常酷的技术,可以用来做一些事情,比如展开/收缩树形菜单或用图形视觉地替换表单元素(由 Ryan Seddon 首创)。

我个人曾经尝试过使用功能性选项卡,并想出了七种不同的方法。大多数方法都围绕着:target伪类选择器,而大多数这些技术都很糟糕。只有一个还不错。它们都有一个主要缺陷,那就是需要使用 URL 哈希,这会导致页面跳到具有匹配 ID 的元素,这完全是不可预期的,跳跃的,而且总体体验很差。

使用单选按钮/:checked技术要好得多,但有一个长期存在的 WebKit 错误,它阻止了伪类选择器和相邻同级组合器一起工作。好消息!从 Safari 5.1 和 Chrome 13 的稳定浏览器版本开始,这个问题已经修复了。

所以,让我们用:checked方法来完成这件事,我认为这是目前和未来几年内最干净的方法。

那是一只虎斑猫吗?懂了吗?!

HTML 结构

整个组的包装器,然后每个选项卡都是一个 div,包含单选按钮(用于功能)、标签(选项卡)和内容 div。

<div class="tabs">
    
   <div class="tab">
       <input type="radio" id="tab-1" name="tab-group-1" checked>
       <label for="tab-1">Tab One</label>
       
       <div class="content">
           stuff
       </div> 
   </div>
    
   <div class="tab">
       <input type="radio" id="tab-2" name="tab-group-1">
       <label for="tab-2">Tab Two</label>
       
       <div class="content">
           stuff
       </div> 
   </div>
    
    <div class="tab">
       <input type="radio" id="tab-3" name="tab-group-1">
       <label for="tab-3">Tab Three</label>
     
       <div class="content">
           stuff
       </div> 
   </div>
    
</div>

CSS 布局

基本上

  1. 隐藏单选按钮(我们不需要看到它们,我们只需要选中或取消选中它们)。
  2. 使选项卡浮动,以便标签落入链接行结构中。
  3. 将内容区域绝对定位在彼此之上。
  4. 当一个单选按钮被选中时,使相邻的内容区域位于顶部,并使用 z-index(在视觉上显示它并隐藏其他内容区域)。
.tabs {
  position: relative;   
  min-height: 200px; /* This part sucks */
  clear: both;
  margin: 25px 0;
}
.tab {
  float: left;
}
.tab label {
  background: #eee; 
  padding: 10px; 
  border: 1px solid #ccc; 
  margin-left: -1px; 
  position: relative;
  left: 1px; 
}
.tab [type=radio] {
  display: none;   
}
.content {
  position: absolute;
  top: 28px;
  left: 0;
  background: white;
  right: 0;
  bottom: 0;
  padding: 20px;
  border: 1px solid #ccc; 
}
[type=radio]:checked ~ label {
  background: white;
  border-bottom: 1px solid white;
  z-index: 2;
}
[type=radio]:checked ~ label ~ .content {
  z-index: 1;
}

这个 CSS 非常轻量级,并且可以通过在 HTML 中添加更多“选项卡”div 来扩展到任意数量的选项卡。

JavaScript

没有,船长!

为什么这种方法很棒

  • 它不使用 :target,因此没有页面跳跃吸附和后退按钮劫持。
  • 它是可访问的。奇怪的单选按钮是用 display: none 隐藏的,所以屏幕阅读器不会看到它们而感到困惑(可能),并且没有实际的内容是用 display: none 隐藏的;
  • 它在 Safari 5.1+、Chrome 13+、Firefox 3.6+、Opera 10+ 和 IE 9+ 中运行。也许在 Chrome、Firefox 和 Opera 中更深入一些,但 Safari 和 IE 绝对是正确的。

为什么这种方法不完美

  • 它需要为选项卡区域设置一个高度,这很糟糕。我觉得可能有一种方法可以解决这个问题,但我还没有找到。
  • 单选按钮方法有点像黑客。
  • 它没有最深入的浏览器支持(IE 9 要求有点高)。如果您需要更深入的支持,请使用 JavaScript。

理解了,明白了,很好

仅仅为了好玩,我在实时演示中为选项卡添加了一些过渡效果。

查看 CodePen 上的
功能性 CSS 选项卡
,由 Chris Coyier (@chriscoyier) 创建。
CodePen 上。

完美的理论未来 – display: stack;

正如我所提到的,单选按钮方法有点像黑客。我们现在能够做到这一点,并且体验非常好,这很酷,但是我们的编码方式并不优雅或直观。Tab Atkins,他编写 CSS 规范,认为display: stack;可能是 CSS 选项卡用户界面的未来