刚开始从事 Web 设计时,我犯了很多错误,也因此获得了进步。那时候没有Smashing Magazine、Can I Use、_ CodePen_,也没有其他我们现在常见的工具。只要有人能告诉一个设计思路,特别是 CSS 前沿方向的,那就谢天谢地了。
今天我的经验已经很丰富了,所以想本着友好、随意、探讨的原则,跟大分享一下 CSS 中的伪类和伪元素。
如果你已经是有经验的 Web 设计者和开发者了,那么一定对本文要讨论的伪类和伪元素有所了解。不过,还是建议你先看看本文后面完整的列表,看有没有一两个你还不知道的?
在真正开始之前,因为我们想讲伪类和伪元素嘛,所以先问个基本的问题:你知道这里的“伪”是什么意思吗?不确定的话,可以参考 Dictionary.com 的定义:
形容词
1. 不是真实的但有其外观;伪装的;假的或欺骗的;骗人的。
2. 差不多,很接近,或尽可能一样。
不用管 W3C 是怎么定义的,反正伪类就是某个元素的一种虚拟状态,或者说一种特有的性质,这种状态或性可以通过 CSS 捕捉到。常见的伪类有::link
、:visited
、:hover
、:active
、:first-child
和:nth-child
。当然这只是一少部分,一会儿我们都会介绍。
伪类是一个冒号(:
)后跟伪类的名字构成的,有时候名字后面还会有一个放在括号里的值。:nth-child
是第几个?
好了,再说伪元素。伪元素是一种虚拟的元素,CSS 把它当成普通 HTML 元素看待。之所以叫伪元素,就因为它们在文档树或 DOM 中并不实际存在。换句话说,我们不会在 HTML 中包含伪元素,只会通过 CSS 来创建伪元素。
以下是几个常见的伪元素::after
、:before
和:first-letter
。伪元素会在本文后面介绍。
伪元素是一个冒号还是两个冒号?
简单回答:多数情况下,都行。
两个冒号(::
)是 CSS3 为了区分::before
、::after
这样的伪元素和:hover
、:active
等伪类才引入的。除了 IE8 及以下版本,所有浏览器都支持两个冒号的伪元素表示法。
不过,有些伪元素只能使用两个冒号,像::backdrop
。
我个人使用一个冒号,为了跟以前的浏览器兼容。当然,不用两个冒号不行的时候,还是要用两个冒号。
这里没有对错,完全看你个人喜好。
不过,我在写这篇文章时查了一下,规范建议使用单冒号表示法,原因也是向后兼容:
请注意 CSS3 中表示伪元素使用双冒号,比如
a::after { … }
,这是为了与伪类区分开。伪类应该是在 CSS 中经常出现的。不过,CSS3 也允许单冒号的伪元素,目的是向后兼容。我们也建议暂时使用单冒号。
如果伪元素同时支持单、双冒号的形式,本文标题会给出两种形式。如果只支持双冒号,那就只有一种形式。
什么时候使用(不使用)生成的内容
通过 CSS 生成内容需要用到 CSS 属性content
和伪元素:before
或:after
。
其中的“内容”(content
)可是纯文本,也可以是一个容器,通过 CSS 操作来显示某种图形或者装饰性元素。本文只介绍第一种内容,即文本。
重要的内容可不要使用生成的内容,原因如下:
屏幕阅读器读不到它
无法选中
如果为了装饰而在生成内容中使用了多余的内容,那么支持 CSS 生成内容的屏幕阅读器会大声地把它读出来,导致用户体验更差
CSS 生成的内容只适用于装饰性、不重要的内容,但也要确保屏幕阅读器能够适当处理它,让使用这些辅助技术的用户不至于分心。这里适用“渐进增强”原则。
在Smashing Magazine上,Gabriele Romanato 为此写过一篇非常棒的文章。
实验性伪类和伪元素
实验性的伪类和伪元素,指的是那些不稳定或没最终定案的伪类和伪元素。它们的语法和行为还可能有变。
不过,加上厂商前缀就可以使用这些实验性的伪类和伪元素。可以参考 Can I Use,以及一些自动加前缀的工具,比如-prefix-free 或 Autoprefixer 就是必备的。
本文会在实验性的伪类和伪元素的名字旁边加上“experimental”标签。
全部伪类和伪元素(按字母顺序)
:active
::after/:after
::backdrop (experimental)
::before/:before
:checked
:default
:dir (experimental)
:disabled
:empty
:enabled
:first-child
::first-letter/:first-letter
::first-line/:first-line
:first-of-type
:focus
:fullscreen (experimental)
:hover
:in-range
:indeterminate
:invalid
:lang
:last-child
:last-of-type
:link
:not
:nth-child
:nth-last-child
:nth-last-of-type
:nth-of-type
:only-child
:only-of-type
:optional
:out-of-range
::placeholder (experimental)
:read-only
:read-write
:required
:root
::selection
:scope (experimental)
:target
:valid
:visited
Bonus content: A Sass mixin for links
好啦,诸位,好戏开场了!
伪类
首先,我们讨论伪类,从状态伪类开始。
状态伪类
状态伪类通常出现在用户执行某个操作的情况下。在 CSS 里,“操作”也可以是“无操作”,比如尚未点过的链接。
下面就有请它们一个一个地上场。
:LINK
:link
伪类表示链接的正常状态,选择那些尚未被点过的链接。建议在其他链接相关的伪类之前声明:link
,它们的顺序为::link
、:visited
、:hover
、:active
。
a:link {
color: orange;}
当然,这个伪类也可以省略:
a {
color: orange;}
:VISITED
:visited
伪类选择点过的链接,应该声明在第二位(在:link
之后)。
a:visited {
color: blue;}
:HOVER
:hover
伪类在用户指针悬停时生效。而且它不只可以用于链接。
它应该在第三位(在:visited
之后)。
a:hover {
color: orange;}
看示例:http://codepen.io/ricardozea/pen/vGEzJK
:ACTIVE
:active
伪类选择被鼠标指针或触摸操作“激活的” 元素,也可以通过键盘来激活,就像:focus
伪类一样。
与:focus
类似,但区别在于:active
只发生在鼠标被按下到被释放的这段时间里。
它应该在第四位(在hover
后面)。
a:active {
color: rebeccapurple;}
:FOCUS
`:focus`用于选择已经通过指针设备、触摸或键盘获得焦点的元素,在表单里使用得非常多。
a:focus {
color: green;}
或者:
input:focus {
background: #eee;}
扩展内容:Sass 中针对链接的混入
如果你用过 CSS 预处理器,那应该对这一部分感兴趣。
(如果你不熟悉 CSS 预处理器,没问题,跳过这一节,直接看下一节吧。)
为了简化 CSS 编码工作,这里介绍一下创建一组基本的链接样式的 Sass 混入(mixin)。
这里的混入没有默认参数,因此我们必须以一种友好的方式,声明链接的全部 4 种状态。
:focus
和:active
伪类的声明通常在一块,当然也可以给它们分开。
注意这个混入不仅仅适用于链接,而是适用于任何 HTML 元素。
这就是我们定义的混入:
@mixin links ($link, $visited, $hover, $active) {
& {
color: $link;
&:visited {
color: $visited;
}
&:hover {
color: $hover;
}
&:active, &:focus {
color: $active;
}
}}
使用方法:
a {
@include links(orange, blue, yellow, teal);}
编译结果:
a {
color: orange;}a:visited {
color: blue;}a:hover {
color: yellow;}a:active, a:focus {
color: teal;}
看示例:http://codepen.io/ricardozea/pen/wMyZQe
结构化伪类
结构化伪类选择通过其他选择符无法选择的文档树或 DOM 中的其他信息。
:FIRST-CHILD
:first-child
伪类选择父元素的第一个子元素。
在下面的例子中,只有第一个li
元素的文本是橙色的。
HTML:
- This text will be orange.
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
CSS:
li:first-child {
color: orange;}
:FIRST-OF-TYPE
:first-of-type
伪类选择父元素容器内任意类型子元素的第一个元素。
在下面的例子中,第一个li
元素和第一个span
元素的文本才是橙色的。
HTML:
- This text will be orange.
- Lorem ipsum dolor sit amet. This text will be orange.
- Lorem ipsum dolor sit amet.
CSS:
ul :first-of-type {
color: orange;}
:LAST-CHILD
:last-child
伪类选择父元素的最后一个子元素。
在下面的例子中,只有最后一个li
元素的文本是橙色的。
HTML:
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
- This text will be orange.
CSS:
li:last-child {
color: orange;}
:LAST-OF-TYPE
:last-of-type
伪类选择父元素容器内任意类型子元素的最后一个元素。
在下面的例子中,最后一个li
元素和最后一个span
元素的文本才是橙色的。
HTML:
- Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. This text will be orange.
- Lorem ipsum dolor sit amet.
- This text will be orange.
CSS:
ul :last-of-type {
color: orange;}
:NOT
:not
伪类也叫取反伪类,它通过括号接受一个参数,一个“选择符”。实际上,这个参数也可以是另一个伪类。
这个伪类可以连缀使用,但不能包含别的:not
选择符。
在下面的例子中,:not
伪类选择与参数不匹配的元素。
HTML:
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
CSS:
应用下面的 CSS,除了类为.first-item
的li
之外的li
元素的文本都是橙色的:
li:not(.first-item) {
color: orange;}
下面看一看“连缀”两个:not
伪类。应用下面的 CSS 规则,除了类为.first-item
的li
和最后一个li
,其他li
都会有黄色背景和黑色文本:
li:not(.first-item):not(:last-of-type) {
background: yellow;
color: black;}
看示例:http://codepen.io/ricardozea/pen/dGmqbg
:NTH-CHILD
:nth-child
伪类根据元素在标记中的次序选择相应的元素。
这个伪类在 CSS 中是用途最广、支持也最广的。
所有:nth
伪类都接受一个参数,这个参数是一个公式。公式可以是一个整数,或者关键字odd
、even
,或者形如an+b
的结构。
对于an+b
:
a
是一个数值(整数)n
就是n
+
是运算符,可以是加号+
或减号-
b
也是一个整数,但只有使用了运算符的时候才会用到
以希腊字母的英文列表为例,以下是 HTML 标记结构:
- Alpha
- Beta
- Gamma
- Delta
- Epsilon
- Zeta
- Eta
- Theta
- Iota
- Kappa
CSS:
选择第 2 个子元素,结果 Beta 会变成橙色:
ol :nth-child(2) {
color: orange;}
从第 2 个子元素起,隔一个选一个,结果 Beta、Delta、Zeta、Theta 和 Kappa 会变成橙色:
ol :nth-child(2n) {
color: orange;}
选择所有偶数个子元素:
ol :nth-child(even) {
color: orange;}
从第 6 个子元素起,隔一个选一个,结果 Zeta、Theta 和 Kappa 会变成橙色:
ol :nth-child(2n+6) {
color: orange;}
看示例:http://codepen.io/ricardozea/pen/adYaER
:NTH-LAST-CHILD
除了是从后往前选择元素,:nth-last-child
跟:nth-child
完全一样。
CSS:
选择倒数第 2 个子元素,只有 Iota 是橙色:
ol :nth-last-child(2) {
color: orange;}
从倒数第 2 个子元素开始,隔一个选一个,结果 Iota、Eta、Epsilon、Gamma 和 Alpha 会变成橙色:
ol :nth-last-child(2n) {
color: orange;}
从后往前,选择所有偶数个子元素:
ol :nth-last-child(even) {
color: orange;}
从倒数第 6 个元素开始,隔一个选一个,因此 Epsilon、Gamma 和 Alpha 会变成橙色:
ol :nth-last-child(2n+6) {
color: orange;}
:NTH-OF-TYPE
:nth-of-type
伪类与:nth-child
类似,主要区别是它更具体了,只针对特定类型的元素。
在下面的例子中,所有容器内的第 2 个p
元素将为橙色。
HTML:
Heading Goes Here
Lorem ipsum dolor sit amet.
This text will be orange.
CSS:
p:nth-of-type(2) {
color: orange;}
:NTH-LAST-OF-TYPE
:nth-last-of-type
伪类是从后往前数,其余跟:nth-of-type
一样。
对于下面的例子,因为是从末尾开始,所以第 1 个段落会变成橙色。
HTML:
Heading Goes Here
Lorem ipsum dolor sit amet.
This text will be orange.
CSS:
p:nth-last-of-type(2) {
color: orange;}
相关资源
建议大家在使用:nth
伪类前,一定要参考下面这两篇不错的文章:
“CSS3 Structural Pseudo-Class Selector Tester” Lea Verou
“:nth Tester” CSS-Tricks
:ONLY-CHILD
:only-child
选择父元素中唯一的子元素。
在下面的例子中,第一个ul
只有一个子元素,因此该子元素将变成橙色。第二个ul
有多个子元素,因此其子元素不会受:only-child
伪类影响。
HTML:
- This text will be orange.
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
CSS:
ul :only-child {
color: orange;}
:ONLY-OF-TYPE
:only-of-type
伪类选择同级中类型唯一的元素,与:only-child
类似,但针对特定类型的元素,让选择符有了更强的意义。
在下面的例子中,第一个ul
只有一个li
元素,因此其文本将为橙色。
HTML:
- This text will be orange.
- Lorem ipsum dolor sit amet.
- Lorem ipsum dolor sit amet.
CSS:
li:only-of-type {
color: orange;}
:TARGET
:target
伪类通过元素的 ID 及 URL 中的锚名称选择元素。
在下面的例子中,当浏览器中的 URL 以#target
结尾时,ID 为target
的文章将被选中。
URL:
http://awesomebook.com/#target
HTML:
:target
pseudo-class
Lorem ipsum dolor sit amet, consectetur adipisicing elit!
CSS:
:target {
background: yellow;}
提示: background:
是background-color:
的简写形式,用于指定颜色时效果一样。
验证伪类
表单验证一直是 Web 设计与开始中最不好搞的。有了验证伪类,可以让用户填写表单的过程更平顺。
有一点要注意,虽然本节介绍的伪类都用于表单元素,但其中有的伪类也可以用于其他 HTML 元素。
下面就来看看这些伪类吧!
:CHECKED
:checked
伪类选择被勾选或选中的单选按钮、多选按钮及列表选项。
在下面的例子中,复选框被勾选后,标签会突出显示,增加了用户体验。
看示例:http://codepen.io/ricardozea/pen/wMYExY
:DEFAULT
:default
伪类从表单中一组类似元素里选择默认的元素(即“提交”按钮。——译者注)。
如果要选择表单中没有类的默认按钮,可以使用:default
。
注意,在表单中使用 Reset 或 Clear 按钮会招致严重的可用性问题,所以除非绝对必要再用。参考下面两篇文章:
“Reset and Cancel Buttons,” Nielsen Norman Group (2000)
“Killing the Cancel Button on Forms for Good,” UX Movement (2010)
看示例:http://codepen.io/ricardozea/pen/WrzJKO
相关链接
css 伪类元素详解(一)
css 伪类元素详解(二)