伪类选择符(pseudo-class selector)
2.6.1拼接伪类
开始之前,先说一下串联。CSS允许把伪类拼接(串联)在一起。例如,可以把有鼠标悬停其上的未访问链接显示为红色,把有鼠标悬停其上的已访问链接显示为红褐色:
a:link:hover {color: red;}
a:visited:hover {color: maroon;}
拼接伪类的顺序其实没什么关系,也可以写成a:hover:link。
2.6.2结构伪类
所有伪类无一例外都是一个冒号(:)后面跟着一个词,而且可以出现在选择符的任何位置。
深入讨论之前,对伪类要明确一点:伪类始终指代所依附的元素。
下面笔者举个例子。2003年,我的第一个孩子出生时,我(像你一样)在网上宣布了这个好消息。有些人对我表示了祝贺,还用CSS开起了玩笑,比如#ericmeyer:first-child选择符。这个选择符的问题是,它选择的是我,而不是我的女儿,而且我必须是爸妈的第一个孩子才行(碰巧我是)。若想正确选择我的第一个孩子,选择符应该是#ericmeyer > :first-child。
选择根元素
结构伪类的简单由此体现::root伪类选择文档的根元素。在HTML中,根元素始终是html。
下面是装饰HTML根元素的一个例子,结果如图2-23所示。
图2-23:装饰根元素
选择空元素
使用:empty伪类可以选择没有任何子代的元素,甚至连文本节点都没有(包括文本和空白)。
注意,为了能正确匹配,从解析的角度来看,元素必须真的为空,没有有空白、可见内容或后代元素。对下面几个元素来说,只有第一个和最后一个能被p:empty匹配:
<p></p>
<p> </p>
<p>
</p>
<p><!—-a comment–></p>
第二个和第三个段落不能被:empty匹配,因为它们不是空的。
选择唯一的子代
如果想选择带超链接的图像,可以使用:only-child伪类。它选择的元素是另一个元素的唯一子元素。假设你想为作为另一个元素唯一子元素的图像加上边框,可以使用:
img:only-child {border: 1px solid black;}
这个规则会应用到符合条件的每一个图像上。
a[href] img:only-child {border: 2px solid black;}
<a href=”http://w3.org/”><img src=”w3.png” alt=”W3C”></a>
<a href=”http://w3.org/”><img src=”w3.png” alt=””> The W3C</a>
<a href=”http://w3.org/”><img src=”w3.png” alt=””> <em>The W3C</em></a>
图2-24:选择作为链接唯一子代的图像
关于:only- child伪类,有两点要注意。首先,前文说过,它始终依附在希望是唯一子元素的那个元素上,而不是父元素。由此引出第二点,即在后代选择符上使用:only-child伪类时,列出的元素不一定是父子关系。
对前面超链接中的图像示例来说,a[href] img:only-child匹配的图像是唯一的子元素,而且是a元素的后代,而不是a元素的子元素。匹配时,那个元素必须是其直接父元素的唯一子元素,而且是链接的后代,但是图像的父元素自身也可以是链接的后代。因此,下面三个图像都能匹配,如图2-25所示。
a[href] img:only-child {border: 5px solid black;}
<a href=”http://w3.org/”><img src=”w3.png” alt=”W3C”></a>
<a href=”http://w3.org/”><span><img src=”w3.png” alt=”W3C”></span></a>
<a href=”http://w3.org/”>A link to <span>the <img src=”w3.png” alt=””>
web</span> site</a>
图2-25:选择链接中作为唯一子代的图像
在三个链接中,图像都是其父元素的唯一子元素,而且都是a元素的后代。因此,示例中的规则能匹配全部三个图像。如果想限制规则,只让它匹配作为a元素唯一子代的图像,要加上子元素连结符,改成a[href] > img:only-child。这样修改之后,图2-25了中的三个图像,只有第一个图像能匹配。
好了,如果想选择超链接中唯一的图像,而链接中还有其他内容该怎么办呢?比如说下面这个链接:
<a href=”http://w3.org/”><b>•</b><img src=”w3.png” alt=”W3C”></a>
这里,a元素有两个子代:b和img。那个图像不再是父元素(超链接)的唯一子元素,因此无法使用:only-child匹配。然而,却能被:only-of-type匹配。下述规则和标记的结果如图2-26所示。
图2-26:选择同胞元素中唯一的图像
这两个伪类之间的区别是,:only-of-type匹配同胞中唯一的那种元素,而:only-child只匹配完全没有同胞的元素。
使用:only-of-type可以放心选择段落中的图像,而不必担心段落中有超链接或其他行内元素:
p > img:only-of-type {float: right; margin: 20px;}
还有一点要澄清,:only-of-type指代的是元素,而不是其他任何东西。以下述规则和标记为例:
p.unique:only-of-type {color: red;}
<div>
<p class=”unique”>This paragraph has a ‘unique’ class.</p>
<p>This paragraph doesn’t have a class at all.</p>
</div>
这里,两个段落都不会被选中。为什么?因为两个段落都是div的后代,因此不可能是唯一一个段落类型。
选择第一个和最后一个子代
:first-child伪类选择一个元素的第一个子元素。以下述标记为例:在这个示例中,第一个p、第一个li,以及strong和em都是相应父元素的第一个子元素。如果有下面两个规则:
p:first-child {font-weight: bold;}
li:first-child {text-transform: uppercase;}
得到的结果如图2-27所示。
图2-27:装饰第一个子代
第一个规则把一个元素中的第一个P元素显示为粗体。第二个规则把一个元素(对HTML来说,必须是ol或ul元素)中的第一个li元素显示为全大写形式。
同样,人们对p:first-child这样的选择符最大的误解是,认为它选择的是p元素的第一个子元素。还记得伪类的特点吗?它为所依附的元素设定某种幽灵类。如果添加真正的类,标记将变成:
<div>
<p class=”first-child”>These are the necessary steps:</p>
<ul>
<li class=”first-child”>Insert key</li>
<li>Turn key <strong class=”first-child”>clockwise</strong></li>
<li>Push accelerator</li>
</ul>
<p>
Do <em class=”first-child”>not</em> push the brake at the same time as the
accelerator.
</p>
</div>
因此,如果想选择一个元素中的第一个em子元素,可以使用em:first-child选择符。与:first-child对应的是:last-child。还以前面的例子为例,如果只修改伪类,得到的结果如图2-28所示。
p:last-child {font-weight: bold;}
li:last-child {text-transform: uppercase;}
<div>
<p>These are the necessary steps:</p>
<ul>
<li>Insert key</li>
<li>Turn key <strong>clockwise</strong></li>
<li>Push accelerator</li>
</ul>
<p>
Do <em>not</em> push the brake at the same time as the accelerator.
</p>
</div>
图2-28:装饰最后一个子代
第一个规则把一个元素中的最后一个P元素显示为粗体。第二个规则把一个元素中的最后一个li元素显示为全大写形式。
有趣的是,这两个伪类结合在一起的效果相当于:only-child。下述两个规则选择的是相同的元素:
p:only-child {color: red;}
p:first-child:last-child {background-color: red;}
选择第一个和最后一个某种元素
除了选择一个元素中的第一个和最后一个子代之外,还可以选择一个元素中某种元素的第一个或最后一个。例如,选择一个元素中的第一个table,而不管它前面有什么元素。
table:first-of-type {border-top: 2px solid gray;}
因此,对图2-29所示的文档结构来说,选中的是圈出的那两个节点。
图2-29:选择第一个表格
在表格中,如果想选择一行中的第一个数据单元格,而不管前面有没有表头,可以这样写:
td:first-of-type {border-left: 1px solid red;}
对下述表格行来说,这将选择每一行中的第一个数据单元格:
<tr>
<th scope=”row”>Count</th><td>7</td><td>6</td><td>11</td>
</tr>
<tr>
<td>Q</td><td>X</td><td>-</td>
</tr>
倘若使用td:first-child,第二行中的td元素能被选中,但是第一行就无法选中了。
与:first-of-type对应的是:last-of-type,它从同胞元素中选择指定种类元素的最后一个。在某种意义上,:last-of-type与:first-of-type特别相似,只不过它是从同胞元素的最后一个开始向前搜索,直到找到指定的元素类型。对图2-30所示的文档结构来说,table:last-of-type选中的是圈出的节点。
图2-30:选择最后一个表格
与前一节末尾所讲的类似,我们可以把这两个伪类连在一起,达到:only-of-type的效果,下述两个规则选择的是相同的元素:
table:only-of-type{color: red;}
table:first-of-type:last-of-type {background: red;}
选择每第n个子元素
CSS为此提供的是:nth-child()伪类。我们可以在括号中填上整数,甚至是简单的代数式,选择任何想选择的子元素。
先看与:first-child等效的:nth-child(1)。对下述示例来说,选中的是第一个段落和第一个列表项目。
p:nth-child(1) {font-weight: bold;}
li:nth-child(1) {text-transform: uppercase;}
<div>
<p>These are the necessary steps:</p>
<ul>
<li>Insert key</li>
<li>Turn key <strong>clockwise</strong></li>
<li>Push accelerator</li>
</ul>
<p>
Do <em>not</em> push the brake at the same time as the accelerator.
</p>
</div>
如果把1改成2,没有段落会被选中,而中间那个(第二个)列表项目会被选中,如图2-31所示。
p:nth-child(2) {font-weight: bold;}
li:nth-child(2) {text-transform: uppercase;}
图2-31:装饰第二个子代
更强大的是,括号中可以使用简单的代数式定义公式。代数式的形式为an+b或an-b,其中a和b是具体的整数,n原封不动。
假设我们想从一个无序列表的第一个列表项目开始,选择每第三个列表项目。此时,可以使用下述选择符,选择第一个和第四个列表项目,如图2-32所示。
这里的n表示0、1、2、3、4,一直到无穷大。浏览器求解3n+1时,得到的结果为1、4、7、10、13等。如果没有+1那部分,只剩下3n,得到的结果是0、3、6、9、12等。因为没有第0个列表项目(与数组不同,HTML元素从第一个数起),所以这个表达式选中的第一个元素是第三个列表项目。
图2-32:装饰每第三个列表项目
正因为元素从1数起,要稍微转个圈才能推出:nth-child(2n)选择的是偶数位的子代,而:nth-child(2n+1)或:nth-child(2n-1))选择的是奇数位的子代。你可以选择记住,也可以使用两个特殊的关键字:even和odd。想从表格的第一行起每隔一行突出显示?可以这么做,结果如图2-33所示。
tr:nth-child(odd) {background: silver;}
图2-33:装饰表格中间隔的行
如果想选择从第9行起的每一行,可以使用下面两个规则中的一个。二者的共同点是都会选择第9行起的每一行,不过后者的特指度更高(参见第3章)。
tr:nth-child(n + 9) {background: silver;}
tr:nth-child(8) ~ tr {background: silver;}
有个与之对应的伪类:nth-last-child()。它的作用与:nth-child()一样,只不过是从一组同胞的最后一个元素开始,从后向前计算。如果想突出显示表格中间隔的行,而且想让最后一行含在其中,可以使用下述规则中的任意一个:
tr:nth-last-child(odd) {background: silver;}
tr:nth-last-child(2n+1) {background: silver;}
只要条件得当,使用:nth-child()和:nth-last-child()可以选择任何元素。下述规则的结果如图2-34所示。
li:nth-child(3n + 3) {border-left: 5px solid black;}
li:nth-last-child(4n – 1) {border-right: 5px solid black; background: silver;}
图2-34:结合:nth-child()和:nth-last-child()
这两个伪类可以串在一起,:nth-child(1):nth-last-child(1)实现:only-child的效果。
选择每第n个某种元素
了解相关模式之后你可能猜到了,:nth-child()和:nth-last-child()伪类有对应的:nth-of- type()和:nth-last-of-type()。例如,可以使用p > a:nth-of-type(even)在一个段落中从第二个超链接起选择间隔的超链接。此时,其他元素(span,strong)都被忽略,只考虑超链接,结果如图2-35所示。
p > a:nth-of-type(even) {background: blue; color: white;}
图2-35:选择偶数位的链接
如果想从最后一个超链接向前数,要使用p > a:nth-last-of-type(even)。
2.6.3动态伪类
除了结构伪类之外,还有一些与结构有关的伪类,不过它们在页面渲染之后根据页面的变化而变化。
超链接伪类
CSS2.1定义了两个只能在超链接上使用的伪类。在HTML中,这两个伪类用在具有href属性的a元素上。
表2-2:链接伪类
伪类 | 说明 |
:link | 指代用作超链接的锚记(即具有href属性),而且指向尚未访问的地址 |
:visited | 指代指向已访问地址的超链接。出于安全考虑,能应用到已访问链接上的样式十分有限。 |
此时,我们可以看一下如何把属性选择符和类选择符与伪类结合在一起使用。假设我们想改变指向站外地址的链接颜色。多数情况下,我们可以使用以特定文本开头的属性选择符。然而,在某些CMS中,所有链接使用的都是绝对URL;此时,可以为每个锚记设定类。比如说:
<a href=”/about.html”>My About page</a>
<a href=”https://www.site.net/” class=”external”>An external site</a>
然后使用下述规则为外部链接应用不同的样式:
a.external:link, a[href^=”http”]:link { color: slateblue;}
a.external:visited, a[href^=”http”]:visited {color: maroon;}
对上述标记中的第二个锚记来说,默认情况下颜色为石蓝色,访问后变成红褐色;而第一个锚记始终显示超链接的默认颜色。
ID选择符也可以跟伪类结合在一起使用:
a#footer-copyright:link{background: yellow;}
a#footer-copyright:visited {background: gray;}
用户操作伪类
CSS中有几个伪类可以根据用户的操作改变文档的外观。这些动态伪类以前普遍用于装饰超链接,不过现在的应用范围宽得多。这些伪类的说明见表2-3。
表2-3:用户操作伪类
伪类 | 说明 |
:focus | 指代当前获得输入焦点的元素,即可以接受键盘输入或以某种方式激活 |
:hover | 指代鼠标指针放置其上的元素,例如鼠标指针悬停在超链接上 |
:active | 指代由用户输入激活的元素,例如用户单击超链接时按下鼠标按键的那段时间 |
可以处于:active状态的元素有链接、菜单项目,以及可以设定tabindex属性的元素。
与:link和:visited类似,这些伪类最常用于超链接。很多网页都有类似下面的样式:
a:link {color: navy;}
a:visited {color: gray;}
a:focus {color: orange;}
a:hover {color: red;}
a:active {color: yellow;}
注意,动态伪类可应用于任何元素,也就是说可用于链接之外的元素。例如,使用下述规则可以突出显示获得键盘输入焦点的表单元素,效果如图2-36所示。
input:focus {background: silver; font-weight: bold;}
图2-36:突出显示获得焦点的表单元素
动态样式引起的问题
动态伪类有些耐人寻味的问题和怪异行为。例如,可以把已访问链接和来访问链接设为相同的字号,而在悬停时把字号增大,如图2-37所示。
a:link, a:visited {font-size: 13px;}
a:hover, a:active {font-size: 20px;}
图2-37:动态伪类改变布局
2.6.4 Ul状态伪类
与动态伪类紧密相关的是用户界面(user-interface,UI)状态伪类,简要说明见表2-4。
表2-4: Ul状态伪类
伪类 | 说明 |
:enbled | 指代启用的用户界面元素(例如表单元素),即接受输入的元豢 |
:disabled | 指代禁用的用户界面元素(例如表单元素),即不接受输入的元素 |
:checked | 指代由用户或文档默认选中的单选按钮或复选框 |
:indeterminate | 指代既未选中也没有未选中的单选按钮或复选框;这个状态只能由DOM脚本设定,不能由用户设定 |
:default | 指代默认选中的单选按钮、复选框或选项 |
:valid | 指代满足所有数据有效性语义的输入框 |
:invalid | 指代不满足所有数据有效性语义的输入框 |
:in-range | 指代输入的值在最小值和最大值之间的输入框 |
:out-of-range | 指代输入的值小于控件允许的最小值或太子控件允许的最大值的输入框 |
:required | 指代必须输入值的输入框 |
:optional | 指代无需一定输入值的输入框 |
:read-write | 指代可由用户编辑的输入框 |
:read-only | 指代不能由用户编辑的输入框 |
启用和禁用的UI元素
可以把一个用户界面元素(或者一组用户界面元素)标记为禁用的。禁用的元素也能显示出来,但是无法选择、激活或与用户交互。未禁用的元素显然是启用的。这两个状态可以使用:enabled和:disabled伪类装饰。常见的做法是装饰禁用的元素,启用的元素不做修饰,不过这两个伪类都有用处,如图2-38所示。
:enabled {font-weight: bold;}
:disabled {opacity: 0.5;}
图2-38:装饰启用和禁用的Ul元素
选择状态
除了启用和禁用之外,某些UI元素还可以选中或不选,HTML中的复选框和单选按钮就是这种。Selectors Level 3为这种状态提供了:checked伪类,比外,还有一个:indeterminate伪类,它匹配的uI元素是可选择但是既未选中也没不选。这些状态如图2-39所示。
图2-39:装饰选中和处于不确定状态的Ul元素
默认选项伪类
:default伪类匹配一组相似元素中取默认值的UI元素。
[type=”checkbox”]:default + label { font-style: italic; }
<input type=”checkbox” id=”chbx” checked name=”foo” value=”bar”>
<label for=”chbx”>This was checked on page load</label>
可选性伪类
:required伪类匹配必填的表单控件,:optional伪类匹配没有required属性的表单控件,或者required属性的值为false的控件。
若想提交表单,表单中匹配:required的元素必须有值,匹配:optional的元素可有值也可以没有值。例如:
input:required { border: 1px solid #f00;}
input:optional { border: 1px solid #ccc;}
<input type=”email” placeholder=”enter an email address” required>
<input type=”email” placeholder=”optional email address”>
<input type=”email” placeholder=”optional email address” required=”false”>
第一个电子邮件地址输入框匹配:required伪类,因为它有required属性。第二个输入框是可选的,因此匹配:optional伪类。第三个输入框也是可选的,因为虽然有required属性,但值是false。
有效性伪类
:valid伪类表示用户输入的值满足全部数据验证条件,而:invalid伪类表示用户输入的值不满足全部数据验证条件。
下面的示例为获得焦点的电子邮件地址输入框设定背景图,一个在输入的地址无效时显一个在输入的地址有效时显示,如图2-40所示。
input[type=”email”]:focus {
background-position: 100% 50%;
background-repeat: no-repeat;
}
input[type=”email”]:focus:invalid {
background-image: url(warning.jpg);
}
input[type=”email”]:focus:valid {
background-image: url(checkmark.jpg);
}
<input type=”email”>
图2-40:装饰有效和无效的UI元素
范围伪类
范围伪类有两个,:in-range和:out-of-range。前者表示用户输入的值在HTML5的min和max属性设定的最小值和最大值范围之内,而后者表示用户输入的值小于控件接受的最小值或大于最大值。
例如,下面几个规则分别装饰一个接受0-1000之间数字的输入框的不同状态:
input[type=”number”]:focus {
background-position: 100% 50%;
background-repeat: no-repeat;
}
input[type=”number”]:focus:out-of-range {
background-image: url(warning.jpg);
}
input[type=”number”]:focus:in-range {
background-image: url(checkmark.jpg);
}
<input id=”nickels” type=”number” min=”0″ max=”1000″ />
:in-range和:out-range伪类只适用于设定了范围的元素。没有范围限制的元素,例如链接或tel类型的输入框,不能被它们中的任何一个匹配。
在下述示例中,输入框中的值将是红色加粗的,因为23在范围内,但是不能被10整除:
input[type=”number”]:invalid {color: red;}
input[type=”number”]:in-range {font-weight: bold;}
<input id=”by-tens” type=”number” min=”0″ max=”1000″ step=”10″ value=”23″ />
可变性伪类
可变性伪类有:read-write和:read-only两个,前者表示输入框可由用户编辑,而后者匹配不能编辑的输入框。只有能被用户编辑的元素才匹配:read-write。例如,在HTML中,未禁用的非只读input元素,以及设定了contenteditable属性的元素匹配:read-write。其他所有元素匹配:read-only。
默认情况下,下面两个规则都不匹配,因为textarea元素是可读可写的,而pre元素对只读的。
textarea:read-only { opacity: 0.75;}
pre:read-write:hover {border: 1px dashed green;}
然而,却匹配下述元素:
<textarea disabled></textarea>
<pre contenteditable>Type your own code!</pre>
因为textarea设定了disabled属性,变成只读的了,所以能应用第一令规则。类似地这里的pre设定了contenteditable属性,现在是可读可写的元素,因此匹配第二个规则。
2.6.5:target伪类
URL中有个片段标识符(fragment identifier),它所指向的文档片段(在CSS中)称为目标(target)。URL片段标识符指向的目标元素可以使用:target伪类特别装饰。
即便不知道“片段标识符”这个术语,你肯定也见过。比如下面这个URL:
http://www.w3.org/TR/css3-selectors/#target-pseudo
这个URL中的target-pseudo部分就是片段标识符,由#符号标记。
借助:target伪类,我们可以突出显示文档中的任何目标元素,或者为不同的目标元素定义不同的样式,例如作为目标的标题使用一个样式,作为目标的表格使用一个样式等。图2-41是:target伪类的实际效果。
*:target {border-left: 5px solid gray; background: yellow url(target.png)
top right no-repeat;}
:target伪类定义的样式在两种情况下不会应用:
- 页面的URL中没有片段标识符。
- 页面的URL中有片段标识符,但是文档中没有与之匹配的元素。
图2-41:装饰一个片段标识符的目标
2.6.6:lang伪类
如果想根据文本使用的语言选择元素,可以使用:lang()伪类。在匹配方式上,:lang()伪类与|=属性选择符类似。假设想让使用法语编写的元素倾斜显示,可以编写下述规则中的任何一个:
*:lang(fr) {font-style: italic;}
*[lang|=”fr”] {font-style: italic;}
2.6.7否定伪类
选择不满足条件的元素,可以使用Selectors Level 3引入的否定伪类:not()。
假设你想装饰class属性不是moreinfo的列表项目。如图2-42所示。
li:not(.moreinfo) {font-style: italic;}
图2-42:装饰没有指定类的列表项目
假设我们想选择所有class为moreinfo,但不是列表项目的元素。结果如图2-43所示。
.moreinfo:not(li) {font-style: italic;}
图2-43:装饰具有特定类,但不是列表项目的元素
用人类语言描述,这个选择符的意思是,“选择的元素,其class属性中包含moreinfo这个词,但不是li元素”。
否定伪类不能嵌套,因此p:not(:not(p))是无效的,将被忽略。
不过,否定伪类可以串在一起,作用相当于“也不是”。例如,你可能想选择class为对link,但既不是列表项目也不是段落的元素:
转载请注明:陈童的博客 » CSS权威指南(第四版)读书笔记——第2章 选择符之伪类选择符