仅使用 CSS3 的选项卡区域

Avatar of Chris Coyier
Chris Coyier 发布

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

当您想到“选项卡”时,您的脑海中可能会立即想到 JavaScript。监视选项卡上的点击事件,隐藏所有面板,显示对应于刚刚点击的选项卡的面板。所有主要的 JavaScript 库都以某种方式处理选项卡。但是,有一种方法可以使用“纯 CSS”来实现相同的想法。就像我们对 CSS 图像切换器 所做的那样,让我们只用 CSS 来处理这个传统上由 JavaScript 处理的项目。

选项卡:一种普遍的设计模式

:target 伪类选择器

这里主要的赋能概念是 CSS 伪选择器 :target。:target 与 ID 选择器一起使用。当当前 URL 包含与该 ID 完全相同的哈希标签时,选择器将匹配。因此,如果当前 URL 为

https://css-tricks.org.cn/#big-bam-boom

并且页面上有一个具有该 ID 的元素

<h1 id="big-bam-boom">Kaplow!</h1>

那么此选择器将匹配

#big-bam-boom:target { color: red; }

如何获得包含此类哈希标签的 URL?您可以使用激活它们的链接

<a href="#big-bam-boom">Mission Control, we're a little parched up here.</a>

浏览器支持 / CSS3

通常,我可能会在这样的教程的结尾添加一小节关于浏览器支持的内容。但在这种情况下,它非常重要,所以让我们现在就解决它。:target 被认为是 CSS3。它在所有主要的当前浏览器中都得到了广泛的支持。当然,我完全支持放弃对 IE 6 的支持,所以如果它在 IE 6 中不起作用(确实不起作用),谁在乎呢?但是,IE 7 或 8 中也不支持 :target。这些浏览器仍然非常受关注,这使得整个教程更偏向于趣味/教育类别,而不是在实际生产环境中使用此技术的类别。

当然,如果您想在生产环境中使用它,一种选择是使用 条件注释 添加 JavaScript 以使其工作。我们不会在这里专门介绍它。

简洁的 HTML

让我们从为即将创建的选项卡区域编写一些漂亮且简洁的 HTML 标记开始

<div class="tabbed-area">

	<ul class="tabs group">
	    <li><a href="#box-one">Tab 1</a></li>
	    <li><a href="#box-two">Tab 2</a></li>
	    <li><a href="#box-three">Tab 3</a></li>
	</ul>
	
	<div class="box-wrap">
	
		<div id="box-one">
		  <!-- box two content -->
		</div>
		
		<div id="box-two">
		  <!-- box two content -->
		</div>
		
		<div id="box-three">
		  <!-- box two content -->
		</div>
	
	</div>

</div>

我认为这非常简洁。即使禁用 CSS,您也会看到一个链接列表,每个链接都会跳转到页面下方与该链接相关的内容的 div。

CSS

我们将选项卡本身设置为链接的水平行。

.tabs { list-style: none; }
.tabs li { display: inline; }
.tabs li a { color: black; float: left; display: block; padding: 4px 10px; margin-left: -1px; position: relative; left: 1px; background: white; text-decoration: none; }
.tabs li a:hover { background: #ccc; }

当您像这样浮动所有链接时,父元素将折叠,因此让我们加入旧的 clearfix 类,以便我们可以在父元素上使用它ul以便它具有自然高度。这里不需要 IE 6 和 7 的 hack,因为这两个浏览器都不支持此技术。

.group:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; }

现在让我们为面板设置非常基本的样式。所有面板都有一个包装 div。这样做的目的是设置一个相对定位上下文,以便我们可以在其中绝对定位面板。所有面板的高度和宽度都相等,并且完全重叠。面板和选项卡都共享相同的 1px 边框。

.box-wrap { position: relative; min-height: 250px; }
.tabbed-area div div { background: white; padding: 20px; min-height: 250px; position: absolute; top: -1px; left: 0; width: 100%; }
.tabbed-area div div, .tabs li a { border: 1px solid #ccc; }

现在,使其发挥作用的神奇部分就像在“目标”面板时调整面板的 z-index 一样简单。

#box-one:target, #box-two:target, #box-three:target {
  z-index: 1;
}

糟糕… 当前选项卡高亮显示怎么办?

到目前为止,我们拥有一个完全功能性的选项卡区域。您点击选项卡,该选项卡中的相应内容就会加载。功能齐全,但不是最有用的 UI。当页面加载时或甚至当您点击查看其他选项卡时,没有任何反馈指示哪个选项卡是当前显示的选项卡。

这是一个相当大的障碍。我找到了一种解决方法,我们将在本文中介绍,**但它很笨拙**。问题的根源在于我们无法“向上”选择元素树。因此,如果我们需要面板具有 ID,那么我们可以在 CSS 中影响的唯一内容是该 div 的后代,当它处于 :target 状态时。例如

#box-four:target a[href="#box-four"] { color: red; }

这将是一种很酷的方式来仅在该面板处于活动状态时选择该特定链接,但截至目前,我们无法做到这一点,因为该链接不是该面板的后代。

我能够解决此问题的唯一方法是实际上只是将导航设为面板的后代。这很糟糕,因为这意味着每个面板都需要重复选项卡……

<div class="box-wrap">

	<div id="box-four">
        <!-- content for panel -->
      
        <ul class="tabs group">
            <li class="cur"><a href="#box-four">Tab 4</a></li>
            <li><a href="#box-five">Tab 5</a></li>
            <li><a href="#box-six">Tab 6</a></li>
        </ul>
	</div>
	
	<div id="box-five">
	    <!-- content for panel -->
	
        <ul class="tabs group">
            <li><a href="#box-four">Tab 4</a></li>
            <li class="cur"><a href="#box-five">Tab 5</a></li>
            <li><a href="#box-six">Tab 6</a></li>
        </ul>
	</div>
	
	<div id="box-six">
	    <!-- content for panel -->
	
        <ul class="tabs group">
            <li><a href="#box-four">Tab 4</a></li>
            <li><a href="#box-five">Tab 5</a></li>
            <li class="cur"><a href="#box-six">Tab 6</a></li>
        </ul>
	</div>

</div>

我知道这并不理想。但是现在列表在面板内部,我们可以对列表项(它是正确的对应链接)使用“current”类并对其进行样式设置。我们将确保当前面板的选项卡导航位于面板上方,并且在其面板处于活动状态时“位于顶部”。

.cur-nav-fix .tabs { position: absolute; bottom: 100%; left: -1px; }
.cur-nav-fix .tabs li a { 
   background: -webkit-linear-gradient(top, white, #eee); 
   background: -moz-linear-gradient(top, white, #eee); 
   background: -ms-linear-gradient(top, white, #eee); 
   background: -o-linear-gradient(top, white, #eee); 
}
#box-four { z-index: 1; }
#box-four:target .tabs, #box-five:target .tabs, #box-six:target .tabs { z-index: 3; }
.cur-nav-fix .tabs li.cur a { border-bottom: 1px solid white; background: white; }

现在有了当前选项卡高亮显示!

更新

如上所述,上面的代码绝对不是一个好的方法。我进一步研究了整个想法,现在下面链接的演示包含了许多不同的想法,包括一些不错的解决方案。

演示和下载

随意使用,但请注意 IE 7 问题。所有 HTML 和 CSS 都在一个页面上,因此如果您想“下载”它,只需将代码复制粘贴到 html 文件中并保存即可。

查看演示

哈希处理

您会在演示中注意到,如果您点击左侧选项卡中的一个选项卡,然后点击右侧选项卡中的一个选项卡,则左侧区域将恢复到其默认幻灯片,而不是保持其当前幻灯片。这一切都归结于 :target 及其与 URL 中哈希的关系。如果没有引入 JavaScript,实际上无法避免这种情况,因此,如果这对您不起作用,您可能应该从一开始就使用 JavaScript。

此外,哈希标签链接在被点击时会“跳转到页面下方”,因此请注意,当您点击选项卡时,浏览器窗口将向下弹出以使该选项卡成为最顶部的元素(如果页面上有足够的滚动空间)。同样,据我所知,如果不使用 JavaScript,就无法避免这种情况。

其他资源