65.9K
CodeProject 正在变化。 阅读更多。
Home

了解 CSS3 选择器,第一部分:结构性伪类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.11/5 (2投票s)

2013 年 2 月 13 日

CPOL

12分钟阅读

viewsIcon

19195

在这个系列的两部分中,我将介绍 CSS3 中的新选择器,首先是结构性伪类。

今天的优秀前端开发人员不仅需要了解如何编写 CSS,还需要了解如何高效地编写 CSS。而“高效”的含义可能取决于您的项目和环境。也许您有一个由多名成员组成的团队在 CSS 方面工作,并且您需要一种高效的协作方式。或者您可能有一个庞大的企业网站,并且需要优化 CSS 以提高速度。您甚至可能在处理一个限制 HTML 访问的遗留系统,这意味着您需要高效的选择器来有效地为没有 ID 或类的元素设置样式。您甚至可能面临所有这些情况以及更多情况。

无论您的 CSS 目标是什么,实现这些目标的最佳方法是了解您的选项,这意味着要理解所有可用的选择器。我们大多数人已经熟悉 ID 和类选择器,并且我在“理解 CSS 选择器”一文中向您介绍了属性选择器的优点。但还有更多内容。

在这个系列的两部分中,我将介绍 CSS3 中的新选择器,首先是结构性伪类

什么是伪类?

CSS 伪类针对的是无法通过组合符或 ID 或类等简单选择器定位的元素。您使用伪类根据元素的属性、状态和相对位置来选择元素。例如,您可能已经熟悉链接状态的伪类

    :link
    :visited
    :hover
    :active
    :focus

CSS3 引入了许多新的伪类,包括结构性伪类,它们根据元素在文档树中的位置以及与其他元素的关系来定位元素。以下是您将在本文中看到示例的结构性伪类的列表。

    :root
    :only-child
    :empty
    :nth-child(n)
    :nth-last-child(n)
    :first-of-type
    :last-of-type
    :only-of-type
    :nth-of-type(n)
    :nth-last-of-type(n)
    :first-child
    :last-child

在详细介绍之前,让我们简要介绍一下您与伪类一起使用的语法。

伪类语法

伪类的语法使用冒号 (:) 后跟伪类名称。

:pseudo-class {}

如果要定位特定元素 (e),请将该元素附加到伪类语法的开头。

e:pseudo-class {}

您甚至可以将伪类与 ID 和类选择器一起使用,如下所示。

#id:pseudo-class {}
.class:pseudo-class {}

数值

一些 CSS3 伪类根据元素在文档树中的特定位置来定位元素。您通过附加到伪类名称的括号 (n) 中的数值来指示位置。

:pseudo-class(n) {}

(n) 的值可以是整数,用于指示元素在文档树中的位置。以下示例针对符合伪类规则的第三个元素。

:pseudo-class(3) {}

您还可以指定数值公式,例如“每五个元素”,这表示为 (5n)

:pseudo-class(5n) {}

此外,您可以通过添加 (+) 或减去 (-) 偏移值来指定偏移公式(允许负值;默认值为零)。

:pseudo-class(5n+1) {}

这些新选择器还允许您通过关键字 odd 和 even 按文档树顺序定位元素。例如,如果您想定位奇数位置的元素,请使用以下方法。

:pseudo-class(odd) {}

应用伪类

既然您已经了解了通用语法,让我们更详细地介绍一些新选择器,并看看使用它们可以实现的样式效果的示例。

:root 

:root 伪类定位根元素 — HTML 元素。考虑以下页面的基本标记。

    <!DOCTYPE html>
        <head>
            <title>Getting to Know CSS3 Selectors</title>
        </head>
        <body>
        </body>
    </html>

如果要为此页面应用主要的背景颜色,并为“容器”显示不同的背景颜色,您可以使用纯 CSS 而无需新标记来实现,如下所示。

    :root{
        background-color: rgb(56,41,48);
    }
    body {
        background-color: rgba(255, 255, 255, .9);
        margin: 0 auto;
        min-height: 350px; 
        width: 700px;
    }

在此示例中,我通过 :root 为 html 元素应用了背景颜色,并通过 body类型选择器应用了容器的样式。这会产生 图 1 中所示的简单视觉布局。

图 1 页面示例,根 html 元素具有深色背景颜色,body 元素具有浅色背景颜色。

:only-child

:only-child 伪类定位作为其父元素唯一子元素的元素。这意味着父元素只包含另一个元素。:only-child 伪类与 :root 伪类不同,后者假定为 HTML 元素。您可以通过将伪类语法附加到元素 (e) 来使用 :only-child 定位任何元素,如下所示。

e:only-child {}

例如,您可能有一段文本,您在其中推广新项目:<h2><b>现已上市!</b>《僵尸生存指南:完全防范活死人》平装版</h2>

如果您想将“现已上市”文本样式化为呼出文本,您可以使用 :only-child 来定位 b 元素,因为它是 h2 的唯一子元素。图 2 显示了您将使用的代码。

    h2 {
        background: rgb(255, 255, 255) url(zombies.png) no-repeat
97% 4%;
        border: 1px solid rgba(125, 104, 99, .3);
        border-radius: 10px;
        color: rgb(125,104,99);
        font: normal 20px Georgia, "Times New Roman", Times,
serif;
        padding: 20px 20px 20px 60px;
        position: relative;
        width: 450px;
    }
    b:only-child {
        background-color: rgb(156,41,48);
        color: rgb(255,255,255);
        display: block;
        font: bold 12px Arial, Helvetica, sans-serif;
        font-weight: bold;
        letter-spacing: 1px;
        padding: 10px;
        text-align: center;
        text-transform: uppercase;
        -moz-transform:  translate(-70px) 
            rotate(-5deg) matrix(1, -0.2, 0, 1, 0, 0);
        -moz-transform-origin: 50px 0;
        -webkit-transform: translate(-70px) 
           rotate(-5deg) matrix(1, -0.2, 0, 1, 0, 0);
        -webkit-transform-origin: 50px 0;
        -o-transform: translate(-70px) 
            rotate(-5deg) matrix(1, -0.2, 0, 1, 0, 0);
        -o-transform-origin: 50px 0;
        -ms-transform: translate(-70px) 
            rotate(-5deg) matrix(1, -0.2, 0, 1, 0, 0);
        -ms-transform-origin: 50px 0;
        transform: translate(-30px) 
            rotate(-5deg) matrix(1, -0.2, 0, 1, 0, 0);
        transform-origin: 50px 0 0;
        width: 150px;
    }
图 2 使用 :only-child 伪类来突出显示标题中的文本并强调它。

此 CSS 会产生 图 3 中看到的视觉呼出效果,而无需向 HTML 添加任何 ID 或类属性。

图 3 产品推广呼出示例。

:empty

:empty 伪类定位没有任何子元素或文本的元素 — 一个空元素,例如:<p></p>。

我个人无法想到一个允许在网站上呈现空元素的场景,但这并不意味着不存在极端情况。就语法而言,您可以使用伪类本身来定位每个空元素。

    :empty {
          background-color: red;
    }

或者,如 :only-child 伪类示例中所示,您可以定位特定元素,如 td。

    td:empty {
          background-color: red;
    }

:nth-child(n)

这是我介绍的第一个利用前面描述的数值的伪类。:nth-child 伪类根据子元素在其父元素中的位置来定位它。例如,一系列博客评论可以具有交替的背景颜色,如图 4 所示。

图 4 具有交替样式的博客文章评论列表示例

此示例的 HTML 只是一个有序列表,如图 5 所示。

    <ol>
        <li>
            <p>March 14, 2012</p>
            <a href="http://nocommonsense.com"><img
src="tdog.jpg" alt="T-Dog" /></a>
            <p><a href="http://nocommonsense.com">T-Dog</a></p>
            <p>C'mon, man, don't give me that gansta s**t!</p>
        </li>
        <li>
            <p>March 13, 2012</p>
            <a href="http://itsallblackandwhite.com"><img
src="rickgrimes.jpg"
                      alt="Rick Grimes" /></a>
            <p><a href="http://itsallblackandwhite.com">Rick
Grimes</a></p>
            <p>You want to kill me, you're going to have to
do better than that
                      wrench.</p>
        </li>
        <li>
            <p>March 13, 2012</p>
            <a href="http://becameawalker.com"><img
src="shanewalsh.jpg"
                     alt="Shane Walsh" /></a>
            <p><a href="http://becameawalker.com">Shane
Walsh</a></p>
            <p>You can't just be the good guy and expect to
live. Not anymore.</p>
        </li>
    </ol>
图 5 博客文章示例的 HTML。

为了给此标记设置样式,我首先使用简单的类型选择器来定位列表项,如图 6 所示。

    li {
        background-color: rgba(194, 181, 158, .5);
        background-image: -webkit-gradient(linear, 
                  left top, left bottom, 
                  from(rgba(194, 181, 158, .7)), 
                  to(rgba(194, 181, 158, 0)));
        background-image: -moz-linear-gradient(top, 
                  rgba(194, 181, 158, .7), 
                  rgba(194, 181, 158, 0));
        background-image: -o-linear-gradient(
                  rgba(194, 181, 158, .7), 
                  rgba(194, 181, 158,
                  0));
        border: 1px solid rgb(194, 181, 158);
        border-radius: 10px;
        margin: 15px 0;
        padding: 25px;
    }
图 6 博客文章示例的样式。

然后,使用 :nth-child() 伪类,我定位了偶数编号的列表项。

    li:nth-child(even){
        background-color: rgba(242, 224, 131, .5);
        background-image: -webkit-gradient(linear, 
                 left top, left bottom, 
                 from(rgba(242, 224, 131, .7)),
                 to(rgba(242, 224, 131, 0)));
        background-image: -moz-linear-gradient(top, 
                 rgba(242, 224, 131, .7), 
                 rgba(242, 224, 131, 0));
        background-image: -o-linear-gradient(
                 rgba(242, 224, 131, .7), 
                 rgba(242,224, 131, 0));
        border: 1px solid rgb(242, 224, 131);
    }

:nth-last-child(n)

:nth-last-child(n) 伪类的工作原理与 :nth-child(n) 类似,但顺序是根据*最后一个*子元素确定的,而不是第一个。使用相同的博客评论示例,请考虑每个列表项中的内容。

    <li>
        <p>March 14, 2012</p>
        <a href="http://nocommonsense.com"><img
src="tdog.jpg" alt="T-Dog" /></a>
        <p><a href="http://nocommonsense.com">T-Dog</a></p>
        <p>C'mon, man, don't give me that gansta s**t!</p>
    </li>

构成评论的每个段落元素都需要进行唯一样式设置,图像也是如此。(参见图 7)。

图 7 此博客评论在其内容中为不同类型的内容显示了不同的样式

对于评论者姓名和链接,我使用 :nth-last-child(n) 伪类和数值来定位列表项中的倒数第二个段落。

    p:nth-last-child(2) {
        clear: left;
        float: left;
        font-size: 12px;
        margin-top: 5px;
        text-align: center;
        width: 80px;
    }

:first-of-type

:first-of-type 伪类定位父元素中特定类型的第一个元素。在博客评论示例中,我可以将日期内容定位为列表项中的第一个段落。

    <li>
        <p>March 14, 2012</p>
        <a href="http://nocommonsense.com"><img
src="tdog.jpg" alt="T-Dog" /></a>
                <p><a href="http://nocommonsense.com">T-Dog</a></p>
        <p>C'mon, man, don't give me that gansta s**t!</p>
    </li>

使用 :first-of-type,我将第一个段落(包含日期)样式化为右对齐,并带有底部边框。

    p:first-of-type {
        border-bottom: 1px solid rgba(56,41,48, .5);   
        float: right;
        font-weight: bold;
        padding-bottom: 3px;
        text-align: right;
        width: 560px;
    }

:last-of-type

:last-of-type 伪类正如其名称所示:定位父元素中的最后一个元素类型。在博客示例中,我可以像这样为最后一个段落中的评论文本设置样式。

  <li> <p>2012 年 3 月 14 日</p> <a href="http://nocommonsense.com"><img src="tdog.jpg" alt="T-Dog" /></a> <p><a href="http://nocommonsense.com">T-Dog</a></p> <p>拜托,伙计,别跟我说那些黑帮话!</p> </li>

图 7 中,您可以看到我是如何使用 :last-of-type 来为最后一个段落设置样式的。这是我使用的 CSS。

    p:last-of-type {
        font-style: italic;
        margin: 50px 10px 10px 100px;
    }

:only-of-type

:only-of-type 伪类定位作为父元素中唯一同类型的子元素。继续以博客评论示例为例,您可以使用此选择器来定位头像。

    <li>
        <p>March 14, 2012</p>
        <a href="http://nocommonsense.com"><img
src="tdog.jpg" alt="T-Dog" /></a>
        <p><a href="http://nocommonsense.com">T-Dog</a></p>
        <p>C'mon, man, don't give me that gansta s**t!</p>
    </li>
CSS:
    img:only-of-type{
        background-color: rgb(255, 255,255);
        border: 1px solid rgba(56,41,48, .5);
        float: left;
        padding: 3px;
    }

:nth-of-type(n)

:nth-of-type(n) 伪类的工作原理与我前面介绍的其他基于数值的伪类类似。此伪类根据元素相对于父元素的位置来定位特定元素类型。您可以在图 8 所示的简单购物车视图中看到您可以通过它实现的样式的示例。

图 8 购物车视图,为不同的表单元格显示独特的样式

此购物车的 HTML 列在图 9 中,它是一个表格。(请记住,表格适用于数据,但请避免将其用于布局)。

    <table cellspacing="0">
        <tr>
            <th>Quanity</th>
            <th>Item</th>
            <th>Price</th>
        </tr>
        <tr>
            <td>1</td>
            <td>The Zombie Survival Guide: Complete Protection
from the Living
                      Dead</td>
            <td>$13.95</td>
        </tr>
        <tr>
            <td>1</td>
            <td>Gerber Apocalypse Kit</td>
            <td>$349.00</td>
        </tr>
        <tr>
            <td>1</td>
            <td>Kookaburra BIG Kahuna 2010 Cricket Bat</td>
            <td>$189.95</td>
        </tr>
        <tr>
            <td>1</td>
            <td>40" Samurai Sword</td>
            <td>$159.00</td>
        </tr>
        <tr>
            <td colspan="2">Subtotal</td>
            <td>$711.19</td>
        </tr>
        <tr>
            <td colspan="2">Tax (7%)</td>
            <td>$49.78</td>
        </tr>
        <tr>
            <td colspan="2">Shipping & Handling</td>
            <td>$25.00</td>
        </tr>
        <tr>
            <td colspan="2">Total</td>
            <td>$785.97</td>
        </tr>
    </table>
图 9 购物车的 HTML。

为了给这些表元素中的几个设置样式,我使用 :nth-of-type(n) 选择器来设置表头和数据单元格的文本对齐方式。例如,Item 表头单元格需要左对齐(默认是居中)。

    <tr>
        <th>Quanity</th>
        <th>Item</th>
        <th>Price</th>
    </tr>

使用 :nth-of-type(n) 选择器,您可以定位该特定子项。

    th:nth-of-type(2) {
        text-align: left;
    }

我可以使用相同的伪类来设置其余文本对齐所需的样式,而无需单个类或 ID。

    th:nth-of-type(3), td:nth-of-type(3) {
        text-align: right;
    }
    th:nth-of-type(1), td:nth-of-type(1) {
        text-align: center;
    }

:nth-last-of-type(n)

:nth-last-of-type(n) 伪类的工作原理与 :nth-of-type(n) 类似,但相对位置是根据最后一个子项而不是第一个子项来偏移的。在购物车示例中,Subtotal、Tax、Shipping 和 Total 行需要独特的样式,如图 10 所示。

图 10 小计、总计和其他行的独特样式

我们来看一下 Subtotal 行,它是表中从底部数起的第四行 (tr)。

    <tr>
        <td colspan="2">Subtotal</td>
        <td>$711.19</td>
    </tr>

我使用 :nth-last-of-type(n) 为该行单元格设置了如图所示的样式。这是我使用的 CSS。

    tr:nth-last-of-type(4) td {
        border-top: 1px solid rgb(56,41,48);
        font-style: italic;
        font-weight: bold;
        text-align: right;
    }

然后,我继续使用此伪类为表的其余行设置样式。

    tr:nth-last-of-type(1) td {
        background-color: rgb(56,41,48);
        color: rgb(255, 255, 255);
        font-size: 14px;
        font-style: italic;
        font-weight: bold;
        padding: 5px 10px;
        text-align:right;
    }
    tr:nth-last-of-type(2) td, tr:nth-last-of-type(3) td {
        font-style: italic;
        text-align: right;  
    }

:first-child

:first-child 伪类定位父元素中任何类型的第一个子元素。在此示例中,让我们考虑一个包含一系列内容元素的侧边栏(图 11)。

图 11 具有不同内容部分的侧边栏

我为此示例使用的标记是一个包含嵌套 aside 元素的容器 div,如图 12 所示。

    <div role="complementary">
        <aside>
            <ul>
                <li><a href="http://youtube.com/whenzombiesattack">Subscribe
to our
                          YouTube channel</a></li>
                <li><a href="http://twitter.com/whenzombiesattack">Follow
us on
                          Twitter</a></li>
                <li><a href="http://facebook.com/whenzombiesattack">Like
us on
                          Facebook</a></li>
            </ul>
        </aside>
        <aside>
            <h3>Newsletter Sign-Up</h3>
            <p>The voodoo sacerdos flesh eater, suscitat mortuos
comedere carnem
                      virus.</p>
            <p><a href="https://codeproject.org.cn/newsletter/">Sign up
now</a></p>
        </aside>
        <aside>
        <h3>From the Blog</h3>
            <p>Zombie ipsum reversus ab viral inferno, nam rick
grimes malum cerebro.
                      De carne lumbering animata corpora quaeritis.
Summus brains sit, morbo
                      vel maleficia? De apocalypsi gorger omero undead
survivor dictum
                      mauris.</p>
            <p><a href="https://codeproject.org.cn/blog/">Read more</a></p>
        </aside>
    </div>
图 12 侧边栏的标记

图 11 所示,侧边栏包含具有定义边框和背景的内容部分。

    aside {
        background-color: rgb(255, 255, 255);
        border: 1px solid rgba(125, 104, 99, .5);
        border-radius: 10px;
        -moz-box-shadow: inset 0 0 20px 
            rgba(125, 104, 99, .5);
        -webkit-box-shadow: inset 0 0 20px 
            rgba(125, 104, 99, .5);
        box-shadow: inset 0 0 20px 
            rgba(125, 104, 99, .5);
        margin-bottom: 20px;
        padding: 25px;
    }

但是,第一个 aside 包含社交媒体图标,没有边框和背景(参见图 11 的顶部)。我使用 :first-child 伪类来定位第一个内容部分。

    aside:first-child {
        background-color: transparent;
        border: 0;
        -moz-box-shadow: none;
        -webkit-box-shadow: none;
        box-shadow: none;
        padding: 0;
    }

:last-child

:last-child 伪类与 :first-child 相反,定位父元素中的最后一个子元素。回到图 11 中所示的侧边栏示例,第一个部分包含一个社交媒体链接列表 (ul)。

    <ul>
        <li><a href="http://youtube.com/whenzombiesattack">Subscribe
to our YouTube
                  channel</a></li>
        <li><a href="http://twitter.com/whenzombiesattack">Follow
us on Twitter</a></li>
        <li><a href="http://facebook.com/whenzombiesattack">Like
us on Facebook</a></li>
    </ul>

这些链接中的每一个都以不同的图标形式呈现在屏幕上,这是通过简单的图像替换技术和精灵图实现的。

    li a {
        background: url(Sprites.png) no-repeat 2px 7px;
        display:block;
        height: 64px;
        text-indent: -5000px;
        width: 64px;
    }

为了给列表中的最后一个链接设置样式,我使用了 :last-child

pseudo-class:
    li:last-child a {
        background-position: -100px 7px;
    }

其余的中间链接使用 :nth-child() 伪类进行样式设置。

    li:nth-child(2) a {
        background-position: -200px 7px;
    }

浏览器支持

好消息是,所有最新版本的浏览器,包括 Internet Explorer 10 和 9,都支持这些 CSS3 伪类。一些较旧的浏览器版本可能对本文中的一些 CSS3 选择器提供有限的支持。

至于早期版本 Internet Explorer 的支持,这实际上应该取决于您的项目。您如何使用任何不支持的选择器?如果纯粹是为了设计和美学目的,请问自己是否可以允许那些 Internet Explorer 用户获得略微降级的体验,同时允许 Internet Explorer 9 和其他浏览器用户获得增强的体验。如果答案是肯定的,请考虑专注于自适应方法来编写 CSS。

如果您需要早期版本的 Internet Explorer 来支持您的 CSS3 伪类,请查看 Selectivzr,这是一个在 Internet Explorer 中模拟 CSS3 伪类支持的 JS 工具。它适用于 jQuery、Dojo、MooTools 和 Prototype。

处理

关于浏览器和 CSS3 伪类的(算是)坏消息是,在浏览器处理选择器的效率方面,伪类处于列表的底部。如果性能和速度对您的项目至关重要,您应该慎用伪类。我建议利用一些测试工具来帮助您最好地优化 CSS 选择器。一些不错的工具有:

何时何地使用

那么,您如何决定使用哪些选择器?答案取决于您的项目。了解您的项目和可用的 CSS 选择器将有助于您做出决定。我在本文中介绍的 CSS3 伪类可能不是您样式表中的“主打”选择器,但它们可能是有价值的工具,尤其是在您无法依赖 ID 和类选择器的情况下。请记住,编写良好的 CSS 是找到实现项目目标的最有效方法。

敬请期待!

请关注“了解 CSS3 选择器”的第二部分。在下一篇文章中,我将介绍 UI 元素状态伪类以及 :target 和 negation 伪类。

本文由 Emily Lewis 撰写。Emily Lewis 是一位自由网页设计师,属于标准ista 类型,这意味着她对语义标记和 CSS、可用性和可访问性等内容充满热情。作为她传播标准的好消息的持续追求的一部分,她在她的博客 A Blog Not Limited 上撰写关于网页设计的文章,并且是 Microformats Made Simple 的作者,也是 HTML5 Cookbook 的特约撰稿人。她还是 Web Standards Sherpa、.net magazine 和 MIX Online 的客座作家。

除了热爱所有网络相关事物外,Emily 还热衷于社区建设和知识共享。她共同创办并共同管理 Webuquerque,这是新墨西哥州针对 Web 专业人士的 Adobe 用户组,并且是 The ExpressionEngine Podcast 的共同主持人。Emily 还应邀在全国各地的会议和活动中发表演讲,包括 SXSW、MIX、In Control、Voices That Matter、New Mexico Technology Council、InterLab 和新墨西哥大学。

在以下平台找到Emily:

HTML5 视频资源

© . All rights reserved.