图解css3:核心技术与案例实战. 2.8 结构伪类选择器-阿里云开发者社区

开发者社区> 华章出版社> 正文

图解css3:核心技术与案例实战. 2.8 结构伪类选择器

简介:

2.8 结构伪类选择器

伪类可以将一段并不存在的HTML当作独立元素来定位,或是找到无法使用其他简单选择器就能定位到的切实存在的元素。因此CSS3给伪类选择器引入一种“结构伪类选择器”。这种选择器可以根据元素在文档树中的某些特性(如相对位置)定位到它们。也就是说,通过文档树结构的相互关系来匹配特定的元素,从而减少HTML文档对ID或类名的定义,帮助你保持代码干净和整洁。

2.8.1 重温HTML的DOM树

所有的结构伪类都是基于HTML文档树的,也称做文档对象模型(DOM),下面简单回顾一下这方面的知识。文档树(Document Tree)是HTML页面的层级结构。它由元素、属性和文本组成,它们都是一个节点(Node),就像公司的组织结构图一样。下面看一个简单的HTML文档。

<!DOCTYPE HTML>

<html lang="en-US">

<head>

  <meta charset="UTF-8">

  <title>HTML DOM树型结构图</title>

</head>

<body>

  <div>

    <ul>

      <li>one</li>

      <li>two</li>

      <li>three</li>

    </ul>

    <div>abc</div>

    <p>para</p>

    <div>def</div>

    <p>para</p>

    <b>ghi</b>

  </div>

</body>

</html>

依据上面的HTML文档,可以绘制一个清晰的DOM结构树,如图2-21所示。

图2-21所示的文档树包含有多个层级是因为HTML元素间的相互嵌套。其中把直接嵌入其他元素的元素被称做那些元素的子元素(Child),例如结构图中的li就是ul的子元素;而随着嵌套的继续深入,它们也就成了后代元素(Descendant),同样,结构图中的li元素就是body元素的后代元素。那些外部元素称为父元素(Parent)(一层之上),例如结构图中的ul元素就是li元素的父元素;有些外部元素称做祖先元素(Ancestor)(两层或以上),例如结构图中的body就是li元素的祖先元素。另外位于相同嵌套层级的元素称为兄弟元素(具有同一父元素节点),例如结构图中的两个段落P元素就是兄弟元素,因为它们具有同一个父元素div。在HTML文档中,一个元素可以同时拥有以上部分甚至所有称谓,正如家谱中的某个成员一样,总的来说这些称谓都是用来描述一个元素与另一个元素的关系。

2.8.2 结构伪类选择器语法

通过回顾HTML的DOM树型结构,清楚了元素之间的关系术语,现在看看有哪些可以建立元素间关系的方法,表2-13列出所有结构伪选择器的详细说明。

表2-13 结构伪类选择器使用语法

选择器     功能描述

选择器     功能描述

E:first-child       作为父元素的第一个子元素的元素E。与E:nth-child(1)等同

E:last-child       作为父元素的最后一个子元素的元素E。与E:nth-last-child(1)等同

E:root       选择匹配元素E所在文档的根元素。在HTML文档中,根元素始终是html,此时该选择器与html类型选择器匹配的内容相同

E  F:nth-child(n)      选择父元素E的第n个子元素F。其中n可以是整数(1、2、3)、关键字(even、odd)、可以是公式(2n+1、-n+5),而且n值起始值为1,而不是0

E  F:nth-last-child(n)       选择元素E的倒数第n个子元素F。此选择器与E  F:nth-child(n)选择器计算顺序刚好相反,但使用方法都是一样的,其中 :nth-last-child(1)始终匹配的是最后一个元素,与:last-child等同

E:nth-of-type(n)        选择父元素内具有指定类型的第n个E元素

E:nth-last-of-type(n)         选择父元素内具有指定类型的倒数第n个E元素

E:first-of-type  选择父元素内具有指定类型 的第一个E元素,与E:nth-of-type(1)等同

E:last-of-type   选择父元素内具有指定类型的最后一个E元素,与E:nth-last-of-type(1)等同

E:only-child       选择父元素只包含一个子元素,且该子元素匹配E元素

E:only-of-type  选择父元素只包含一个同类型的子元素,且该子元素匹配E元素

E:empty   选择没有子元素的元素,而且该元素也不包含任何文本节点

 

表2-13中,只有“:first-child”属于CSS2.1,此外其他的结构伪类选择器都是CSS3的新特性,为我们提供精确定位到元素的新方式。表中只是告诉我们CSS3结构伪类选择器的概念性的知识,有时候看起来不太好理解,针对图2-21的HTML DOM树型结构,将CSS3结构伪类选择器结合起来理解,如图2-22所示。

 

图2-22 CSS3结构伪类选择器

2.8.3 浏览器兼容性

CSS3结构伪类选择器在主流浏览器下运行都非常的完美,只是在IE 9以下版本的浏览器中无法正常运行,浏览器兼容性如表2-14所示。

在本例中颜色交替只是一个很小的视觉增强,IE 8及之前版本的用户看不到也无妨,而对于圆角、渐变之类的效果,IE将直接忽略它们,使用直角或纯色显示,看起来没有任何异常之处。

表2-14 结构伪类选择器浏览器兼容性

选择器                                         

E:first-child       9 +√        √     √     √     √

E:last-child       9 +√        √     √     √     √

E:root       9 +√        √     √     √     √

E  F:nth-child(n)      9 +√        √     √     √     √

E  F:nth-last-child(n)       9 +√        √     √     √     √

E:nth-of-type(n)        9 +√        √     √     √     √

E:nth-last-of-type(n)         9 +√        √     √     √     √

E:first-of-type  9 +√        √     √     √     √

E:last-of-type   9 +√        √     √     √     √

E:only-child       9 +√        √     √     √     √

E:only-of-type  9 +√        √     √     √     √

E:empty   9 +√        √     √     √     √

 

想为IE 8及之前的版本提供一个解决方案,需要用到JavaScript脚本。例如要实现例中的Zebra表格效果,网上有大量的脚本可以帮你。最适合的脚本还是取决于项目本身,可以通过Google搜索“Zebra Stripe JavaScript”、“Zebra Stripe PHP”或者其他更符合需求的关键词。

还可以使用一个脚本为IE增加高级选择器的支持,然后使用选择器实现需要的效果。例如jQuery脚本库,还有Dean Edwards的ie9.js,此外还有前面介绍的Selectivizr脚本配合其他JavaScript脚本库一起使用。

2.8.4 结构伪类选择器中的n是什么

在结构伪类选择器中,有4 个伪类选择器接受参数n。

:nth-child(n)

:nth-last-child(n)

:nth-of-type(n)

:nth-last-of-type(n)

在实际应用中,这个参数n可以是整数(1、2、3、4)、关键字(odd、even),还可以是公式(2n+1、-n+5),但参数n的起始值始终是1,而不是0。换句话说,当参数n的值为0时,选择器将选择不到任何匹配的元素。

根据上面所述,将结构伪类选择器中的参数按常用的情况划分为七种情形。

1.参数n为具体的数值

这个数值可以是任何大于0的正整数,例如“:nth-child(3)”将选择一个系列中的第3个元素。

2.参数n为表达式“n*length”

选择n的倍数,其中n 从0开始计算,而length为大于0的整数。当length为整数1时,将选择整个系列中的所有元素,直到元素耗尽无法选择为止。因为length在实际运用中常为大于1的正数,表达式才具有实际意义,例如“:nth-child(2n)”。

n=0时,2×0=0,不选中任何元素;

n=1时,2×1=2,选中系列中的第2个元素;

n=2时,2×2=4,选中系列中的第4个元素;

n=3时,2×3=6,选中系列中的第6个元素;

……

以此类推,直到元素耗尽无法选择为止。

3.参数n为表达式“n+length”

选择大于或等于length的元素,例如“:nth-child(n+3)”。

n=0时,0+3=3,选中系列中的第3个元素;

n=1时,1+3=4,选中系列中的第4个元素;

n=2时,2+3=5,选中系列中的第5个元素;

n=3时,3+3=6,选中系列中的第6个元素;

……

以此类推,直到元素耗尽无法选择为止。

4.参数n为表达式“-n+length”

选择小于或等于length的元素,例如“:nth-child(-n+3)”。

n=0时,-0+3=3,选中系列中的第3个元素;

n=1时,-1+3=2,选中系列中的第2个元素;

n=2时,-2+3=1,选中系列中的第1个元素;

n=3时,-3+3=0,不选择任何元素;

n=4时,-4+3=-1,不选择任何元素;

……

以此类推,当值小于或等于0时将不选择任何元素。

5.参数n为表达式“n*length+b”

其中b是您想设置的偏移值,其表示隔length个元素选中第n*length+b个元素,例如“:nth-child(2n+1)”。

n=0时,2×0+1=1,选中系列中的第1个元素;

n=1时,2×1+1=3,选中系列中的第3个元素;

n=2时,2×2+1=5,选中系列中的第5个元素;

n=3时,3×2+1=7,选中系列中的第7个元素;

……

以此类推,直到元素耗尽无法选择为止。

6.参数n为关键词“odd”

选择系列中的奇数(1、3、5、7)元素,其效果等同于“:nth-child(2n-1)”和“:nth-child(2n+1)”。

7.参数n为关键词“even”

选择系列中的偶数(2、4、6、8)元素,其效果等同于“:nth-child(2n)”。Sitepoint.com也制作了一个关于“:nth-child(n)”的参考指南供大家对照参考,如表2-15所示。

表2-15 结构伪类表达式的计算列表

n       2n+1         4n+1         4n+4         4n     5n-2 -n+3

0       1       1       4       —     —     3

1       3       5       8       4       3       2

2       5       9       12     8       8       1

3       7       13     16     12     13     —

4       9       17     20     16     18     —

5       11     21     24     20     23     —

 

以上几种情形也适用于“:nth-last-child(n)”、“:nth-of-type(n)”和“:nth-last-of-type(n)”三种结构伪类选择器。

尽管上面公式算出来的数值(1、3、5、7)也可以手动给系列元素中的第1、3、5、7元素添加对应类名,但这样做不仅耗时费力,还容易遗忘,代码不整洁使维护过程非常痛苦。如果想在已经存在的项目中插入另外一个,不得不对插入处之后的项目全部重新定义新的类名,因为插入后新的序号被打乱。而用CSS3的结构伪类选择器“:nth-child(n)”代替类名,跟踪元素系列的序号变化并自动匹配将会更为准确、高效,而且维护非常方便。

或许会觉得这样的数学计算太麻烦,从而产生对“nth-child(n)”系列结构伪类选择器的抵触。大家不用担心,线上有一些不错的工具,可以通过更改数值为即时查看它是如何影响页面样式的,这将有助于更好地了解“:nth-child(n)”系列结构伪类选择器的作用,例如:

Lea Verou制作的工具。

Chris Coyier制作的工具。

Neal Grosskopf制作的工具。

2.8.5 结构伪类选择器的使用方法详解

结构伪类选择器是CSS3选择器最具特色的一部分内容,同时也是CSS3选择器中最出色的一部分内容。通过前面的内容,大家对CSS3的结构伪类选择器有了初步的了解,但是完全理解它们,还是需要一定的实例,下面分别介绍CSS3的结构伪类选择器的具体使用方法。

为了更好地实例化,先创建一个简单的列表结构,并附上一些简单的样式。

<!DOCTYPE HTML>

<html lang="en-US">

<head>

  <meta charset="UTF-8">

  <title>CSS3结构伪选择器的使用</title>

  <style type="text/css">

    *{

      margin: 0;

      padding: 0;

    }

    ul {

      margin: 50px auto;

      width: 400px;

      list-style: none outside none;

    }

    li {

      display:inline-block;

      margin: 5px;

      padding: 5px;

      width:50px;

      height: 50px;

      font: bold 30px/50px arial;

      background: #000;

      color: #fff;

      border-radius: 50px;

      text-align: center;

    }

  </style>

</head>

<body>

  <ul>

    <li>1</li>

    <li>2</li>

    …

    <li>20</li>

  </ul>

</body>

</html>

页面初始效果如图2-23所示。

1.:fist-child的使用

“:first-child”允许定位某个元素的第一个子元素,例如想改变列表中的第一个“li”的背景色,代码如下。

ul>li:first-child {

  background-color: green;

}

在没有这个选择器之前,需要在列表中的第一个“li”加上一个类名,例如“first”,然后给添加对应的样式。

ul>li.first {

  background-color: green;

}

其实这两种最终效果是一样的,如图2-24所示。后面这种需要在html标签中增加一个额外的class类名,只是一个地方还好处理,如果是多处都具有这样的效果,给html添加类名的方法其弊端明显可见。

在实际项目中这样的运用也是常有的事,例如博客侧边栏的标题“h2”顶部都有一个“margin”,用来区分标题和它们前面区块的内容,但是第一个标题“h2”不需要顶部“margin”值,就可以使用下面的代码。

.aside > h2 {

  margin-top: 15px;

}

.aside>h2:first-child {

  margin-top: 0;

}

上面看到的是使用“:first-child”来移除标题顶部的间距,当然也可以用来移除元素底部的间距,此时在不支持“:first-child”的浏览器中,布局并不会因此而破坏掉,它只会看起来有些不同(顶部或底部间距没清除)。但是,如果使用“:first-child”来移除一个浮动元素的左边距或右边距,在不支持“:first-child”的浏览器中,布局将会被破坏掉。

2.:last-child的使用

“:last-child”与“:first-child”作用类似,不同的是“:last-child”选择的是元素最后一个子元素。就拿上面的例子来说,改变列表中最后一个“li”的背景色,使用这个选择器如下所示。

ul>li:last-child {

  background-color: blue;

}

和“:first-child”一样,以前为了实现上面的效果,都是在列表中的最后一个“li”添加一个类名“last”,并在此类添加样式,其最终效果都是一样的,如图2-25所示。

在实际的Web项目中,“:last-child”的用处也非常广泛。例如在一个导航条中每个导航项都有一个右边框效果,但最后一个不想要这个右边框,此时就可以使用“:last-child”。

#nav > li {

  …

  border-right: 1px solid #ccc;

}

#nav > li:last-child {

  border-right: none;

}

另一个较常见的就是在博客制作中,假设“post”中最后一段不需要底部“margin”值,代码如下。

.post > p:last-child {

  margin-bottom: 0;

}

3.:nth-child的使用

“:nth-child()”用来定位某个父元素的一个或多个特定的子元素。“:nth-child()”可以接受参数n,而且n可以是数值,也可以是表达式和关键词。有关于“n”是什么?大家可以参考“结构伪类选择器中的n是什么”。在这一节中,通过实例加深理解“:nth-child(n)”。

(1) :nth-child(3)

参数n是一个具体的整数值,例如“:nth-child(3)”表示选择某元素下的第3个子元素,(这里的整数3可以根据自己的需要来定义)。接上面的实例,如果需要改变列表项中第3个“li”元素的背景色,就可以直接这样使用。

ul>li:nth-child(3){

  background-color: yellow;

}

这样一来,列表中的第3个li的背景就变成黄色了,如图2-26所示。

上面仅是列表中存在li一种子元素,但是如果列表中第3个li之前还有其他的子元素,例如DIV元素(当然这样写HTML是一种不规范的写法,此处仅用来说明问题,不提倡这样去写HTML结构),“ul>li:nth-child(3)”还会选中列表中的第3个li元素吗?先不做任何回答,改变一下实例的代码。

<!DOCTYPE HTML>

<html lang="en-US">

<head>

  <meta charset="UTF-8">

  <title></title>

  <style type="text/css">

    ul {

      list-style: none outside none;

      padding: 10px;

      background: green;

      width: 400px;

    }

    li {margin-bottom: 10px;border: 1px solid orange;}

    div {margin-bottom: 10px;border: 1px solid blue;}

  </style>

</head>

<body>

  <ul>

    <li>1</li>

    <li>2</li>

    <div>div</div>

    <div>div</div>

    <li>3</li>

    …

    <li>10</li>

  </ul>

</body>

</html>

页面的初步效果如图2-27所示。

同样,加上以下代码。

ul>li:nth-child(3){

  background-color: yellow;

}

保存上面样式后刷新浏览器,并没有得到想要的效果,列表中的第3个li背景色没有为此改变。因为在ul里面有其他类型的元素(不是li),它也会算作是列表的子元素。就上面的实例,li:nth-child(3)并不存在,列表的第3个子元素是div而不是li,此时如果还想改变第3个列表的背景色,就必须改变“:nth-child()”中的值(或者使用:nth-of-type())。拿这个实例来说,第3个li是列表中的第5个子元素,将上面的代码改为以下形式。

ul>li:nth-child(5){

  background-color:yellow;

}

接下来用效果来证明是不是需要的效果,如图2-28所示。

通过上面两个实例的对比,大家清楚“ul>li:nth-child(3)”表达的并不是一定选择列表ul元素中的第3个子元素li,仅有列表ul中第3个li元素前不存在其他的元素,命题才有意义,否则就会造成开始的问题,不会改变列表第3个li元素的背景色。

(2) :nth-child(n)

参数n是一个简单的表达式,取值从0开始计算的,到什么时候结束不知道,如果在实际应用中直接这样使用,将会选中父元素中的所有子元素。接着前面列表的案例,在代码中加入以下代码。

ul>li:nth-child(n){

  background-color: orange;

}

效果如图2-29所示。

意     “:nth-child(n)”中参数只能是n,不可以使用其他的字母代替,不然会没有任何效果。

 

(3) :nth-child(2n)

该选择器是“:nth-child(n)”的一种变身,可以选择n的2倍数,当然其中“2”可以换成需要的数字。

ul>li:nth-child(2n){

  background-color: blue;

}

这样列表中的偶数项都将被选中,其效果如图2-30所示。

这个时候大家有没有想到关键词“even”呢?是的,“:nth-child(2n)”和使用关键词“:nth-child(even)”得到的效果是一样的。它们在实际项目中用来制作一些突出效果是非常方便的。例如制作斑马线表格,给偶数行设置一个不同的背景色。

table tr:nth-child(even){...}

或者:

table tr:nth-child(2n){...}

(4) :nth-child(2n+1)

该选择器是在“:nth-child(2n)”基础上演变过来的,前面说了“:nth-child(2n)”和“:nth-child(even)”是选择偶数,就可以在其基础上加1或减1,将偶数变成奇数。例如:

ul>li:nth-child(2n+1){

  background-color: blue;

}

这样列表中奇数列背景色都将变成蓝色,如图2-31所示。

“:nth-child(2n+1)”和“:nth-child(2n-1)”选择的是父元素中排序为奇数的子元素,同时选择奇数还可以直接使用关键词“odd”来实现(“:nth-child(odd)”)。换句话说,“:nth-child(odd)”、“:nth-child(2n+1)”和“:nth-child(2n-1)”三个选择器定位的元素是完全相同的。

使用奇数选择器制作斑马线表格是很常见的,不同之处是改变的是表格奇数行的背景色,当然也可以同时使用偶数和奇数,制作一个靓丽的斑马线表格。

table tr:nth-child(odd) {...}/*设置表格奇数行样式*/

table tr:nth-child(even){...}/*设置表格偶数行样式*/

(5) :nth-child(n+5)

这个选择器从父元素中的第5个子元素开始选择,这里的数字可以自己定义。例如:

ul>li:nth-child(n+5){

  background-color: blue;

}

此时列表中第5个li元素开始直到最后一个li元素,其背景都将变成蓝色,如图2-32所示。

                  

         图2-31 :nth-child(2n+1)效果   图2-32 :nth-child(n+5)效果

例如在博文有一个“今日焦点”区块,想让今日点击量落后于第三的文章序列号标注红色,此时这个选择器就非常的方便了,如图2-33所示。

只要将选择器中的数字变成需要的即可。

.post-hot-today li:nth-child(n+4){color: red;}

(6) :nth-child(-n+5)

该选择器刚好和“:nth-child(n+5)”相反,选择父元素中第1个到第5个子元素,如果不太清楚,只要把两个表达式的计算值对比就非常清楚了。同样通过“:nth-child(-n+5)”来选择列表中前5个子元素li。

ul>li:nth-child(-n+5){

  background-color: blue;

}

上面代码刚好与图2-32效果相反,如图2-34所示。

同样,想在博客“热门博文”区块内把排在前三的文章进行特殊标注,如图2-35所示。

选择器的使用如下所示。

.post-hot li:nth-child(-n+3){...}

(7) :nth-child(4n+1)

选择器实现某父元素的子元素隔几选一的效果,例如“:nth-child(4n+1)”实现的就是隔3个子元素选中一个子元素,直到所有元素耗尽为止。其中“4n+1”可以根据自己的需求进行修改。在前面实例基础上,使用“:nth-child(4n+1)”来改变li的效果色为蓝色。

ul > li:nth-child(4n+1){

  background-color: blue;

}

此时整个列表项的第1、5、9、13、17项背景色变成蓝色,如图2-36所示。

上面展示的是“:nth-child”结构伪类选择器的几种使用方法,大家在实际应用中根据需求使用不同的表达式,从而满足需求。

4.:nth-last-child的使用

“:nth-last-child”和“:nth-child”相似,只是这里多了一个“last”,作用和“:nth-child”有所区别。从某父元素的最一个子元素开始计算来选择特定的元素。接着上面的实例代码,来看“:nth-last-child”选择器的实例。

ul>li:nth-last-child(4){

  background-color: blue;

}

上面的代码选择了ul列表中倒数第4个li元素,如图2-37所示。

“:nth-last-child”可以像“:nth-child”一样使用表达式、关键词等,不同的是,“:nth-last-child”起始位置是从父元素的最后一个子元素开始计算。注意“:nth-last-child”使用关键词odd、even,由于起始位置不同,“:nth-last-child”使用关键词odd和even所得到的顺序刚好相反。

 

图2-37 :nth-last-child(4)效果

简单来说,使用“:nth-child(odd)”选择的是奇数项,而使用“:nth-last-child(odd)”选择的却是偶数项,如图2-38所示。同样,使用“:nth-child(even)”选择的是偶数项,而使用“:nth-last-child(even)”选择的是奇数项,如图2-39所示。

 

图2-38 :nth-child(odd)与:nth-last-child(odd)对比

 

图2-39 :nth-child(even)和:nth-last-child(even)对比

可知,“:nth-child(odd)”与“:nth-last-child(even)”选择的元素是相同的,而“:nth-child(even)”和“:nth-last-child(odd)”选择的元素相同。

扩展阅读 “:nth-child”与“:nth-last-child”的区别

“:nth-child”和“:nth-last-child”两个选择器的使用方法和所起的作用是一样的,用来选择某父元素中的特定子元素,同时所有的子元素不分类型,而且所有出现的子元素都会按文档流的先后顺序来排序。同时它们之间有一个很明显的区别。

“:nth-child”选择器选择的子元素是从第一个子元素开始算起;

“:nth-last-child”选择器选择的子元素却是从最后一个子元素开始算起。

5.:nth-of-type的使用

“:nth-of-type”和“:nth-child”类似,不同的是它只计算父元素中指定的某种类型的子元素。当某个元素中的子元素不单单是同一种类型的子元素这,使用“:nth-of-type”选择器来定位于父元素中某种类型的子元素是非常的方便和有用。正如前面看到的实例,当ul列表中不仅仅有子元素li,而且还有别的子元素是DIV,使用ul>li:nth-child(3)来选择第3个li元素时,无法选择,如图2-27所示。通过改变选择器“:nth-child”的变量参数值为5,才可以选中列表中的第3个子元素li,如图2-28所示。但是使用“:nth-of-type”,就不用改变其变量参数值。

ul>li:nth-of-type(3){

  background-color:orange;

}

效果如图2-40所示。

同“:nth-child”的具体使用方法一样,“:nth-of-type”也具有参数设置,这个参数也是n,它可以是具体的整数值,也可以是表达式和关键词。

在Web应用中,“:nth-of-type”在以下场景中可以使用。

营造一种有随意感的界面,例如改变每张图片的旋转角度;

使文章中的图片交替着向左向右浮动;

为一篇文章的头一段设置不同的样式,例如首字下沉;

为一个定义列表的条上使用交替样式;

制作图表。

此外,还有更多的使用场景。一起来看看其中几个场景下的具体使用。

在Web页面的设计中,常常给某种类型元素设置一些特殊的样式,以达到突出的目的。例如,将一篇文章第一个段落的文字设置大一些,以前通常是在第一个段落P添加一个类名“first”,然后设置其字号比别的段落大一些。使用“:nth-of-type”选择器,就能轻松的改变文章中第一个段落的字号。

.node p:nth-of-type(1){

  font-size: 1.5em;

}

也许想在一篇文章中把奇数图片左对齐,偶数图片右对齐,如图2-41所示。

首先想到给文章中的图片加一个left或right类名,然后分别给这两个不同的类名定义不同的对齐方式。这样的做法毫无疑问是正确的,但现在说最佳的做法是使用“:nth-of-type”来实现。

 

图2-41 图片对齐效果

.article img:nth-of-type(odd){

  float: left;

  margin-right: 10px;

}

.article img:nth-of-type(even){

  float: right;

  margin-left: 10px;

}

它在IE 8及以下浏览器是不被支持的,但可以借助JavaScript库来实现,例如Keith Clark编写的Selectivizr脚本,或者直接无视不支持的浏览器,例如Simon Foster就使用了“:nth-of-type”为它收集的45RPM唱片制作的一份漂亮的图表,采用“:nth-of-type”为每种不同的流派设置一个不同的背景图片。下面是Simon Foster站上截取的一段代码。

ul#genre li:nth-of-type(1) {

   width:32.9%;

  background:url(images/orangenoise.jpg);

}

ul#genre li:nth-of-type(2) {

   width:15.2%;

  background:url(images/bluenoise.jpg);

}

ul#genre li:nth-of-type(3) {

  width:13.1%;

  background:url(images/greennoise.jpg);

}

图2-42是从站点截取的效果。

 

图2-42 “For The Record”站点使用:nth-of-type的效果

扩展阅读 “:nth-child”和“:nth-of-type”的区别

“:nth-child”和“:nth-of-type”两者之间的区别对于初学者来说很是头痛的问题,为了更好地帮助大家区分使用方法,特意在此加以区分。首先创建一个简单的HTML结构。

<div class="post">

  <p>我是文章中的第一个段落</p>

  <p>我是文章中的第二个段落</p><!--  ==我要变成红色的字== -->

</div>

接下来,使用“:nth-child”和“:nth-last-child”选择段落并改变其文字颜色。

.post>p:nth-child(2){color:red;}

.post>p:nth-of-type(2){color:red;}

上面的代码都把“post”中的第二段文字变成大红色,是不是代表这两个选择器就是一样的呢?其实不然。“:nth-child”仅从字面上来解释,其包含了两层意思。首先是一个段落元素,而且这个段落是父元素“DIV”的第二个子元素;而“:nth-of-type”从字面上解释是“选择父元素DIV的段落二”。

上面一段话看来很晕,有没有更好的方法来区分它们呢?有的,把上面的HTML结构改变一下,在两个段落前加上一个标题“h1”。

<div class="post">

  <h1>我是标题一</h1>

  <p>我是文章中的第一个段落</p>

  <p>我是文章中的第二个段落</p> <!--  ==我要变成红色的字== -->

</div>

前面的样式不变,但结构却完全不同了。“p:nth-child(2)”并没有选择段落二,而是选择了段落一,从而也就没有达到需要的效果。

.post>p:nth-child(2){color: red;} /*第一个段落变成红色,不是我们需要的效果*/

“p:nth-child(2)”选错了段落,但“p:nth-of-type(2)”却工作正常,选择的还是段落二,实现想要的效果。

.post>p:nth-of-type(2){color:red;}/*改变段落二文字色为红色,是我们需要的效果*/

如果在“h1”标题后面添加一个“h2”标题,此时“p:nth-child(2)”将无法选择任何元素,因为此时“DIV”的第二个子元素并不是段落一“P”,所以无法选择任何元素。但“p:nth-of-type(2)”依然能正常工作,因为选择的始终是“DIV”中的段落二“P”。

大家只需要记住一点:“:nth-child”选择的是某父元素的子元素,这个子元素并没有指定确切的类型,同时满足两个条件时方能有效果,其一是子元素,其二此子元素刚好处在那个位置;“:nth-of-type”选择的是某父元素的子元素,而且这个子元素是指定类型。

“:nth-child”虽然常见,但却脆弱,正如前面的示例所示,随时被其他子元素给挤出选择的范围。而“:nth-of-type”不常见,但在选择某种类型的子元素时,更稳定,更可靠。

6.:nth-last-of-type的使用

“:nth-last-of-type”和“:nth-of-type”一样,用来选择父元素中指定的某种子元素类型,但它的起始方向是从最后一个子元素开始,而且使用方法可以像前面提到的“:nth-last-child”一样使用。

例如选择一篇文章的最后一个段落,会很快地想到“:last-child”和“:nth-last-child(1)”这两个选择器,但是文章中并不常常都是以段落来结束,这个时候“:nth-last-of-type”就能快速、准确定位到最后一个段落。

.article p:nth-last-of-type(1){...}

也可以更加的聪明一些,在一个块级选择器中结合多种这样的伪类选择器。举个例子,让文章中除了第一个和最后一个的所有图片左浮动,这个时候多种伪类的选择器就非常的实用。

.article img:nth-of-type(n+2):nth-last-of-type(n+2){

  float:left

}

在这个组合型选择器中,第一部分“:nth-of-type(n+2)”从第2个图片开始定位,选择了文章中所有图片,除了第一张;第二部分“:nth-last-of-type(n+2)”从文章中倒数第2张图片开始定位,选择了文章中所有图片,除了最后一张。因为这两个选择器并非互相排斥的,可以同时使用它们,这样就可以立刻排除第一张和最后一张图片,达到想要的选择效果。

扩展阅读 “:nth-of-type”和“:nth-last-of-type”的区别

“:nth-of-type”和“:nth-last-of-type”都是结构伪类选择器,它们的作用也是一样的,都是用来选择某父元素中指定类型的子元素,区别就是,“:nth-of-type”选择的某类型子元素是从前往后排序计算,而“:nth-last-of-type”选择的某类型子元素是从后向前排序计算。

7.:first-of-type和:last-of-type的使用

“:first-of-type”和“:last-of-type”这两个选择器类似于“:first-child”和“:last-child”,不同之处就是指定了元素的类型。换句话说,“:first-of-type”是用来定位一个父元素下的某个类型的第一个子元素;而“:last-of-type”用来定位一个父元素下的某个类型的最后一个子元素。

通过前面的学习了解到,“:nth-of-type(1)”用来选择父元素指定类型第一个元素,其实可以使用“:fist-of-type”来代替。同样,可以使用“:last-of-type”来代替“:nth-last-of-type(1)”。

8.:only-child的使用

“:only-child”表示一个元素是它父元素的唯一子元素。换句话说,匹配元素的父元素中仅有一个子元素。来看一个简单的例子,在post列表中,有的只有一个段落,有的不只一个段落。

<!DOCTYPE HTML>

<html lang="en-US">

<head>

  <meta charset="UTF-8">

  <title>:only-child的使用</title>

  <style type="text/css">

    .post {

      width: 300px;

      margin: 20px auto;

      padding: 5px;

      border: 1px solid #ccc;

    }

    p {

      background: green;

      color: #fff;

      border: 1px solid orange;

      padding: 5px;

    }

  </style>

</head>

<body>

  <div class="post">

    <p>我是第一个段落</p>

    <p>我是第二个段落</p>

  </div>

  <div class="post">

    <p>我就一个段落</p>

  </div>

</body>

</html>

上面的实例中运用了一些初步样式,其初步页面效果如图2-43所示。

下面是关键时候了,使用“:only-child”看看两个post中的段落p会有什么样的变化。

.post>p:only-child {

  border-width:2px;

  background-color:#000;

}

使用“:only-child”后的效果如图2-44所示。

                  

         图2-43 页面初步效果         图2-44 :only-child器使用效果

很明显的两个列表中只有一个段落p的改变了样式,也就是说“:only-child”仅能匹配父元素中一个子元素,而且这个子元素是唯一的。

9.:only-of-type的使用

“:only-of-type”用来选择一个元素是它的父元素的唯一一个相同类型的子元素。这样说或许不太好理解。换一种说法,“:only-of-type”表示一个元素有很多个子元素,而其中只有一个子元素是唯一的,使用“:only-of-type”就可以选中这个唯一类型子元素。

Devsnippet制作了一个demo,只有一张图片与一个容器中有多张图片的不同样式风格,下面代码是从demo中截取的。

div > img {

   background:#DCE8F5 none repeat scroll 0 0;

   border:3px solid #96C8E5;

   float:left;

   margin:5px;

   padding:5px;

}

div > img:only-of-type {

  border:3px solid #E71F58;

  float:none;

  margin:10px;

  padding:10px;

}

从代码中可以明显的得知,div中的图片左浮动,但div中仅有一图片类型时,此图片样式不浮动,而且还将改变对应的外边距和内边距值,效果如图2-45所示。

10.:empty的使用

“:empty”用来选择没有任何内容的元素,这里“没有任何内容”指的是一点内容都没有,哪怕是一个空格。这个选择器用来处理动态输出内容方面非常方便。例如想高亮提示用户搜索出来的结果为空时,就可以这样使用。

#results:empty{background-color:#fcc;}

2.8.6 实战体验:CSS3美化表格

对于数量大的表格,普通的设计极易影响用户的阅读体验。例如长时间地阅读数据量大的表格容易引起视觉的疲劳,会诱发错行误读等问题。因此,Web设计师要设计一个表格,不仅需要考虑表格的外观,而且要提高用户的体验。

Zebra是经典的数据表格设计样式,主要从易用性的角度来考虑,以提高用户浏览数据的速度和准确度。传统的做法是在表格的行中分奇数和偶数,为相应的行添加类名,然后通过类名来控制表格单元格的背景色。当然,这种设计给前端工作人员带来很多不便之处,例如动态插入行,就需要重新为行设置类名,也给维护带来很多困难。

然而采用CSS3结构伪类选择器后,一切都是那么简单而轻松。

<!DOCTYPE HTML>

<html lang="en-US">

<head>

  <meta charset="UTF-8">

  <title>CSS3美化表格</title>

  <style type="text/css">

*{margin: 0;padding: 0;}

body {

  padding: 40px 100px;

}

.demo {

  width: 600px;

  margin: 40px auto;

  font-family: 'trebuchet MS', 'Lucida sans', Arial;

  font-size: 14px;

  color: #444;

}

/*表格的默认设置*/

table {

  *border-collapse: collapse; /* IE 7 and lower */

  border-spacing: 0;

  width: 100%;

}

 

/*========制作圆角表格========*/

.bordered {

  border: solid #ccc 1px;    /*给表格添加边框*/

  border-radius: 6px;        /*设置表格圆角*/

  box-shadow: 0 1px 1px #ccc;/*表格阴影设置*/

}

.bordered tr {

  -o-transition: all 0.1s ease-in-out;

  -webkit-transition: all 0.1s ease-in-out;

  -moz-transition: all 0.1s ease-in-out;

  -ms-transition: all 0.1s ease-in-out;

  transition: all 0.1s ease-in-out;       

}

.bordered .highlight,

.bordered tr:hover {

  background: #fbf8e9;/*表格行的悬浮状态效果*/

}

.bordered td,

.bordered th {

  border-left: 1px solid #ccc;

  border-top: 1px solid #ccc;

  padding: 10px;

  text-align: left;

}

.bordered th {

  /*表格表头添加渐变背景色*/

  background-color: #dce9f9;

  background-image: -webkit-gradient

       (linear, left top, left bottom, from(#ebf3fc), to(#dce9f9));

  background-image: -webkit-linear-gradient(top, #ebf3fc, #dce9f9);

  background-image: -moz-linear-gradient(top, #ebf3fc, #dce9f9);

  background-image: -ms-linear-gradient(top, #ebf3fc, #dce9f9);

  background-image: -o-linear-gradient(top, #ebf3fc, #dce9f9);

  background-image: linear-gradient(top, #ebf3fc, #dce9f9);

  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,

           startColorstr=#ebf3fc, endColorstr=#dce9f9);

  -ms-filter: "progid:DXImageTransform.Microsoft.gradient (GradientType=0,

           startColorstr=#ebf3fc, endColorstr=#dce9f9)"; 

  box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;/*表格表头设置内阴影*/

  border-top: none; 

  text-shadow: 0 1px 0 rgba(255,255,255,.5);/*表格表头设置文字阴影*/

}

/*使用:first-child去除表格每行的第一个单元格的左边框*/

.bordered td:first-child,

.bordered th:first-child {

  border-left: none;

}

/*使用:first-child设置表格表头第一个单元格仅左上角为圆角*/

.bordered th:first-child {

  border-radius: 6px 0 0 0;

}

/*使用:last-child设置表格表头最后一个单元格仅右上角为圆角*/

.bordered th:last-child {

  border-radius: 0 6px 0 0;

}

/*使用:first-child和:last-child设置表格最后一行的第一个单元格左下角为圆角*/

.bordered tr:last-child td:first-child {

  border-radius: 0 0 0 6px;

}

/*使用:last-child设置表格最后一行的最后一个单元格右上角为圆角*/

.bordered tr:last-child td:last-child {

  border-radius: 0 0 6px 0;

}

 

/*=======制作Zebra表格(斑马线表格)效果==========*/

.zebra td,

.zebra th {

  padding: 10px;

  border-bottom: 1px solid #f2f2f2;

}

/*使用:nth-child(even)给表格的奇数行添加背景和阴影效果*/

.zebra .alternate,

.zebra tbody tr:nth-child(even) {

  background: #f5f5f5;

  box-shadow: 0 1px 0 rgba(255,255,255,.8) inset;

}

.zebra th {

  text-align: left;

  text-shadow: 0 1px 0 rgba(255,255,255,.5);

  border-bottom: 1px solid #ccc;

  background-color: #eee;

  background-image: -webkit-gradient(linear,

           left top, left bottom, from(#f5f5f5), to(#eee));

  background-image: -webkit-linear-gradient(top, #f5f5f5, #eee);

  background-image: -moz-linear-gradient(top, #f5f5f5, #eee);

  background-image: -ms-linear-gradient(top, #f5f5f5, #eee);

  background-image: -o-linear-gradient(top, #f5f5f5, #eee);

  background-image: linear-gradient(top, #f5f5f5, #eee);

  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,

           startColorstr=#f5f5f5, endColorstr=#eeeeee);

  -ms-filter: "progid:DXImageTransform.Microsoft.gradient (GradientType=0,

           startColorstr=#f5f5f5, endColorstr=#eeeeee)";

}

/*使用 :first-child设置表格表头第一个单元格左上角为圆角*/

.zebra th:first-child {

  border-radius: 6px 0 0 0;

}

/*使用 :last-child设置表格表头最后一个单元格右上角为圆角*/

.zebra th:last-child {

  border-radius: 0 6px 0 0;

}

.zebra tfoot td {

  border-bottom: 0;

  border-top: 1px solid #fff;

  background-color: #f1f1f1;

}

/*使用 :first-child设置表格脚部第一个单元格左下角为圆角*/

.zebra tfoot td:first-child {

  border-radius: 0 0 0 6px;

}

/*使用 :last-child设置表格脚部最后一个单元格右下角为圆角*/

.zebra tfoot td:last-child {

  border-radius: 0 0 6px 0;

}

  </style>

</head>

<body>

</body>

</html>

通过上面的代码,在现代浏览器中就能看到两个美化后的表格,如图2-46所示。

 

图2-46 CSS3美化表格

图2-46的表格效果是不是很清晰。我们需要知道这样的表格是怎么制作出来的,下面就一起来细化以上代码。

以前表格的圆角效果是通过图片来模拟,制作相当麻烦。有了CSS3后,这些都变得那么容易,只要使用border-radius就可以(这个属性后面章节会详细介绍)。制作表格圆角时还有一个技巧,在制作表格圆角效果之前,有必要先完成一步。border-collapse的默认值是separate,需要将其设置为0,如下所示。

table{

  *border-collapse: collapse;/*IE 7 and lower*/

   border-spacing:0;

}

接下来一起看表格圆角实现的代码。

/*==整个表格设置了边框,并设置了圆角==*/

.bordered {

  border: solid #ccc 1px;

  border-radius: 6px;

}

/*==表格头部第一个th需要设置一个左上角圆角==*/

.bordered th:first-child {

  border-radius: 6px 0 0 0;

}

/*==表格头部最后一个th需要设置一个右上角圆角==*/

.bordered th:last-child {

  border-radius: 0 6px 0 0;

}

/*==表格最后一行的第一个td需要设置一个左下角圆角==*/

.bordered tr:last-child td:first-child {

  border-radius: 0 0 0 6px;

}

/*==表格最后一行的最后一个td需要设置一个右下角圆角==*/

.bordered tr:last-child td:last-child {

  border-radius: 0 0 6px 0;

}

在table中设置一个边框,为了让表格具有圆角效果,需要在表格四个角的单元格上分别设置圆角效果,并且其圆角的半径弧度与表格的圆角半径弧度大小一样。反之,如果在table上没有设置边框,只需要在表格四个角的单元格设置圆角,就能实现圆角效果,例如Zebra表格。

/*==表格头部第一个th需要设置一个左上角圆角==*/

.zebra th:first-child {

  border-radius: 6px 0 0 0;

}

/*==表格头部最后一个th需要设置一个右上角圆角==*/

.zebra th:last-child {

  border-radius: 0 6px 0 0;

}

/*==表格最后一行的第一个td需要设置一个左下角圆角==*/

.zebra tfoot td:first-child {

  border-radius: 0 0 0 6px;

}

/*==表格最后一行的最后一个td需要设置一个右下角圆角==*/

.zebra tfoot td:last-child {

  border-radius: 0 0 6px 0;

}

例中的表格除了使用了CSS3的圆角效果之外,还使用了box-shadow制作表格的阴影效果,使用text-shadow制作表格表头的文字阴影效果,使用transition制作hover悬浮高亮的过渡效果,以及使用gradient制作表头的渐变效果。这些属性还不清楚如何使用,大家不必太担心,本书后续章节会一一介绍。

版权声明:如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:developerteam@list.alibaba-inc.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:

华章出版社

官方博客
官网链接