当您想到“选项卡”时,您的脑海中可能会立即想到 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,就无法避免这种情况。
其他资源
- 保持目标 – 来自 Think Vitamin 的精彩文章,不幸的是缺少其演示。不过,它涵盖了一些非常聪明的技巧。
- W3C 关于 :target 的规范
哈哈,很棒的文章,还加入了你特有的幽默!
IE 再次出击
IE 再次出击,确保我们无法将其用于客户*
不要问我为什么打错了字。
有趣的文章,但我有点吹毛求疵。这难道不是将布局与行为混淆了吗?这是一个巧妙的技术;不幸的是,它不受 CSS 的目的和机制的支持。这就是为什么它有一些文章中提到的缺点。
是的,但这确实是一个“CSS技巧”,不是吗? :)
一个好技巧,# 搞砸了它
:hover 从技术上讲也是行为,但我们必须务实。
甚至在 W3C 的官方网站上有一个示例,说明如何使用 :target 进行选项卡导航。
你可以用 3 个 div(id 为 box-one、box-two、box-three)包装所有内容,并定位它们。然后你将实际内容包装在另一个 div 中,并执行以下操作
#box-one:target #box-one-content {
z-index: 1;
}
#box-one:target a[href="#box-one"] {
color: red;
}
当然可以用一些高级的 CSS3 选择器做得更整洁。
这样做的原因是为了只需要一组选项卡。顺便说一句,好文章 :)
是的,我认为这很有潜力!更多的额外标记,但只是包装器而不是重复的内容,这要好得多。
对于一个有趣/教育类的类别演示——干得漂亮。
我认为这不是一篇好文章。只是实现了 CSS3 的工作原理。即使是解决方案(当前选项卡突出显示)也很脏。我认为这不会应用于任何 Web 应用程序。
我对此有一些顾虑。对于像这样的多选项卡内容,用户可能会在选项卡之间来回切换。但是现在,如果他们想点击“后退”以返回到包含选项卡内容的那个页面之前的页面,它只会将他们送回最后选择的选项卡,因此可能不适合主要内容。
有趣的文章。我永远不会将其用于任何东西,但看到 CSS3 的灵活程度很有趣,即使对于它不打算用于的事情也是如此。所以对于那些反对者来说,不,它不适用于生产环境,而只是一个使用 css 的有趣技巧。
使用 :target 来突出显示内容很好;就像在那些很长的常见问题列表中,当你向下跳转页面以查找答案时。你可以为目标区域提供不同的背景颜色,以帮助引导眼睛到页面上的正确位置。
我想说在生产环境中将其用于类似的东西是可以的。
绝对可以,因为这将是渐进增强,在我的书中,这在生产环境中始终是可以的。
IE8 不支持 :target 伪类,因此这在任何版本的 IE 中都无法使用
http://msdn.microsoft.com/en-us/library/cc351024(VS.85).aspx
我不记得有人在乎过。
无论如何,这是一个很酷的技巧。如果我们因为 IE 做不到而停止做事,我们现在仍然在使用闪烁标签。
我的评论指出了文章内容中的一处小错误。似乎文章现在已经更新以反映这一点,因此我的评论现在可能没有意义了。
我想 Coyier 先生在乎过。
你从哪里想出所有这些好点子的?
你可以通过将其放在最后,在框后面,并使用“~”来定位兄弟元素来解决导航重复问题。这并不理想,但稍微不那么麻烦。
http://n-son.com/misc/csstabs.html#box-one
但是,该演示仅在 Firefox 中有效,出于某种原因,Webkit 不会更新选项卡,除非你在点击它后刷新。
太棒了!必须学习更多关于兄弟选择器的知识。顺便说一句,在 Opera 中也有效。
很遗憾 :target 在 IE 中不受支持,它可以成为突出显示锚定链接等的实用小技巧。但我认为它不适合你向我们展示的选项卡系统,它很棒,不要误会我的意思,但我认为这是错误的方法。
目前,JavaScript 很容易使用,并且只需要很少的额外代码即可创建非常酷的选项卡区域,这些区域允许你毫无问题地来回切换,并带有淡入淡出效果等。
我相信很快我们就可以创建完全由 CSS/XHML 组成的网站,无需任何外部编码,并且可以使用更简单的方法在多个平台上创建带有效果的选项卡。
这很棒,只有一个问题。
假设第一个选项卡最终高度为 900px(带有其文本),而其他选项卡大约为 400px。当你从该选项卡切换回另一个选项卡时,该选项卡仍然存在,位于其他选项卡下方。
此外,如果浏览器窗口太小,它会将页面向下移动。
我尝试在一个只能使用 CSS 和 HTML 作为描述的网站上使用类似(并且稍微简单一些)的方法,虽然它有效(它仍然有效),但我认为最好使用 JS 来处理此类事情。
此处的 :target 选择器可以用于执行超出 z-index 的操作。
想想高度、溢出和(也许)位置!
这将解决你的问题。
嘿,Chris,
我们也可以使用 webkit-gradients 吗? ;-)
很棒的教程。感谢分享!
谢谢,Chris!
我已经能够想到一些实际用途(事实上,我一直在考虑如何采用图像切换器并使用相同的技术制作选项卡)
我的朋友说这些很糟糕。
我认为它本来可以做得更好。花费更多的时间和精力来完成它。Chris,你可以做得更好。
我的朋友说,如果你不喜欢这个网站,就不用读了。
用 Jemaine Clement 的话说,“你能对你的批评更有建设性吗?”
这些类型的东西仅仅是一种概念证明的方式。Chris 甚至表示,这更多是为了信息/教育目的,而不是生产环境。
Jared,拜托。
我很好奇,我们如何使用 JavaScript 或 jQuery 实现 :target 选择器的等效项?
你可以使用以下方法获取哈希值
var hash = window.location.hash;
然后编写一个选择器来查找链接(jQuery)
$("a[href='"+hash+"']").whatever();
或者只是具有该 ID 的内容……我认为这应该可以……
$(hash).whatever();
实际上,jQuery 锚点选择器不起作用,因为变量“hash”将等于 #(变量)。
$("a"+hash).whatever();
但是,此代码应该没问题..
是的,但 #variable 正是你想要的,因为哈希符号是 jQuery 中的 ID 选择器。就像 http://www.site.com#header,window.location.hash = “#header”,这是一个完美的 jQuery 选择器。对吧?
是的,先生,这正是我想要的。非常感谢,我只是想指出你发布的锚点选择器不会出于这个原因而工作。
我无法将 href 设置为类似 #variable 的原因是,jQuery 变量已设置,并且单击带有哈希标签的链接不会刷新页面。我必须链接到一个页面以重定向到具有正确哈希标签的页面。
除了你提到的 IE 浏览器之外,:target 在各个浏览器中都得到了很好的支持。Opera 浏览器也存在一个持续了很长时间的 bug,点击后退按钮不会触发 :target 伪类的任何变化。
我自己在 CSS3 手风琴演示 和创建 CSS 灯箱效果 中广泛使用了 target,它有一些非常强大的功能。
我再试着粘贴一下。论坛似乎转换了它。
我不确定我上面发布的方法是否能在 IE 中完美运行,但我确实在过去让它完美运行过。不幸的是,我找不到那些文件了。
目前,我无法在 Mac 上使用 winebottler 运行 IE,但我成功地使用过一台 Windows 电脑(我现在没有了)和多个 IE 版本让它工作。
在阅读了评论之后,就像上面许多人所说,我永远不会觉得在大多数客户的网站上使用 :target 或 hack 标签方法很舒服。只有在极少数情况下,它才能被认为是有帮助或合适的。
@Chris:演示现在都乱了。除了一个页面上 2 个或更多标签区域由于页面长度而无法工作之外,点击标签时标签栏会超出视野。
例如:我点击标签 3,窗口跳转到该框,标签栏超出视野。这不仅是一个缺点,而且我认为它挑战了标签区域的核心原则,即切换到其他标签。
这对可用性来说是不可接受的损失。
只有示例 3 和 6 没有这个问题,其余的在我看来甚至不应该被考虑为选项,就这样!
:) 我的两分钱
不,我完全同意,“向下跳转”的影响是其中很大一部分,而那些向下跳转到面板并切断标签本身的标签确实会降低可用性。但看到演示中的这一点非常重要。
一如既往,很棒的作品!
太棒了;)
这是我的版本 http://www.webstuffshare.com/2010/01/updated-pure-css-tab-menu/
感谢 Chris,这是任何初出茅庐的网页设计师的又一个宝贵资源。我最近偶然发现了你的网站,从那以后我每天都会访问,因为有如此多的片段和教程可以让我学习一段时间。再次感谢
“当你像那样将所有链接浮动时,父元素会折叠,所以让我们加入旧的 clearfix……”
你知道 CSS3 _真正_需要什么吗?
一种合理、正式认可、定义明确且受支持的清除浮动的方法!
我建议使用 overflow:envelop 或 overflow:contain-content
Chris,感谢你更新示例页面。我已使用你的示例来测试 ie-css3 的下一个当前版本,并可以报告它们在 IE8 中按预期工作(但在 5.5 – 7 中不工作)。
当然,IE8 对 :target 的支持是基于开发人员准备接受 JavaScript 解决方案来解决此问题的假设。
偷偷的想法。我认为现在不是使用这种解决方案的好时机:)。
我如何下载它