如何使用:before和:after伪元素?
如果你有一直密切关注各个关于网页设计的博客,你大概会注意到,:before和:after伪元素已经在前端开发界得到越来越多的关注,并且是有很好的理由。特别是,有个博主(位于伦敦的一位开发者Nicolas Gallagher ),他对伪元素的应用尝试,给伪元素带来震撼的曝光机会。
这84个GUI图标是用伪元素和语义化的HTML创建的。查看demo
为了补充和加强本次的曝光(并利用发展趋势带来的好处),我整理了一份自认为比较完整的关于伪元素的“前世今生”。本文针对那些见识过伪元素一些应用的酷炫效果,想自己尝试做,但是要先了解这门CSS技术的读者。
虽然CSS规则包括其它的伪元素,但是在本文,当我提到伪元素的时候,我特别指的是:before和:after这两个。
伪元素是做什么的?
伪元素所做的就像它的字面意思一样,它创造一个虚假的元素,并把它插到目标元素里面内容的之前和之后。
基本语法
:before和:after伪元素的代码很容易编写,这是个例子:
1
2 3 4 5 6 7 |
#example:before {
content: "#"; } #example:after { content: "."; } |
关于这个例子,要注意两点。
第一,我们同时用:before和:after对同样的目标元素起作用。如它们都作用于id为example的元素上。
第二,如果没有content属性(它是生成内容模型所定义的一部分),伪元素是无效的。也就是,如果要使用伪元素选择器来定义,那么就需要有content属性,否则你加任何其它的样式属性都是无意义的。
在这个例子里,将会有伪内容,显示于id为example的元素的内容之前或/和之后。
关于这个语法,要强调几点。
可以给content属性留空,创建一个“零内容”的盒子。如下:
1
2 3 4 5 6 |
#example:before {
content: ""; display: block; width: 100px; height: 100px; } |
但是,content这个标签是不能被移除的,否则,伪元素就不起作用了。这个“零内容”,需要给content属性一个空内容的双引号。
你也许会注意到,:before和:after也可以写为::before和::after,其实这两者没有什么区别,只是用在CSS3中来区分伪类(单冒号)和伪元素(双冒号)。
最后一点要说明的是,你可以应用一个伪元素,没有作用于任何的目标元素。如下:
1
2 3 |
:before {
content: "#"; } |
这个是有效的写法,但是一点用处也没有。
插入内容有什么特性?
如上描述,插入的内容在页面的源代码是看不到的。它只在CSS里面可见。
同样,插入的内容默认的是一个内联(inline)元素。所以,要给插入元素一个height\padding\Margin等,需要先给元素定义为块状(block级)的元素。
以下就开始简单描述如何定义伪元素。
在这个例子里面,我对应用到插入元素的样式进行了高亮。伪元素就是这样的独特,即是可以在同样的声明块中同时定义插入内容和样式。
另外,要知道的一点是,CSS的继承规则同样适用于插入元素。比如应用在body里面的字体、字体大小等这些样式,插入元素和其它元素一样,会继承这样的样式。
同样,和其他元素一样,伪元素不继承父级如padding\margin这样的属性。
插入在什么之前和之后?
你或许会迷惑,插入元素是插入到哪里?你一看到:before和:after或许会认为就是在其所作用的目标元素的之前或之后。然而,事实并不是这样。
要插入的内容,会被放置于目标元素的里面,作为它的一个子元素,并且它会显示在目标元素里面内容的之前或之后。
要理解这点,看看这个代码:
1
2 |
<p class=box>Other content.
</p> |
样式:
1
2 3 4 5 6 7 8 9 10 11 |
p.box {
width: 300px; border: solid 1px white; padding: 20px; } p.box:before { content: "#"; border: solid 1px white; padding: 2px; margin: 0 10px 0 0; } |
在HTML里面,你所看到的是个段落(p),这个p有个class为box,其里面的内容是“other content”(就像你会在html的源代码里面所看到的)。在CSS里面,这个p被定义样式有width\padding\border。
然后,再看看伪元素的定义。在这个例子里面,这个插入内容是放到到段落(p)里面的内容之前的。被定义的样式有border\padding\margin。
看看这个图就明白了。
外框是段落,内容插到段落里面内容的前面而不是到段落的前面。
插入非文本的内容
我之前提过可以给content属性设为空字符,或者一个文本内容。其实你还有其它的两种选择,就是给它加特定的内容,如下:
第一,可以包含一个URL指向一个图片,在这里,你可以定义一个Data URI,就像你想定义一个背景图片一样。
1
2 3 |
p:before {
content: url(image.jpg); } |
第二,你还有另外一个选择就是加上attr(x)这种形式的函数。根据定义,这个函数为选择器对象返回一个由属性X的值生成的字符串
1
2 3 |
a:after {
content: attr(href); } |
attr()函数取得所定义的属性的值,并把它作为文本变成可以插入的伪内容。
浏览器支持情况
像对待其它的一些前端技术一样,开发者们关注的重点之一就是浏览器支持啦。在这点上,看似问题还没那么大。:before和:after的浏览器支持情况如下:
Chrome 2+,
Firefox 3.5+ (3.0有部分支持),
Safari 1.3+,
Opera 9.2+,
IE8+ (尚有些小bug),
大部分的移动设备浏览器。
这里唯一真正的问题(毫无疑问)就是完全不支持的IE6和IE7。所以,如果你的目标用户是网页开发者群(或者其它较少使用IE浏览器的群体),那么你就大胆用吧。
另外,说到伪元素的安全性,幸运的是,缺乏一个伪元素并不会引发什么功能上的问题。伪元素大多数是用来生成修饰性的内容,在不支持伪元素的浏览器里面,不会引发重大问题。所以,如果你的目标群体是IE浏览器使用者占大多数的,在某个程度上,你依然可以使用这个属性。
几个提醒
如前面所述,伪元素的内容不会在DOM结构中显示。这些元素不是真正的元素。它们在大多数的辅助设备中是不可访问的。所以对网页的使用性和可用性很关键的内容,要尽量避免使用伪元素来生成。
另外,像Firebug这样的开发者工具,并不会显示由伪元素生成的内容。所以,如果滥用伪元素,会引发网页调试过程效率低下和网页维护不方便等问题。
([更新]在评论里提及的两点:你可以使用chrome的开发者工具来查看关于伪元素的样式,但这个元素不显示在DOM里面。还有一点,Firebug1.8已经添加了对伪元素的支持。)