1,什么是伪类、伪元素
无论是伪类还是伪元素,都属于CSS选择器的范畴。
用标准里的话说:CSS 引入伪类和伪元素的概念是为了实现基于文档树之外的信息的格式化。
2,伪类与伪元素的区别
这里我大可以列一个表格,把所有的伪类和伪元素分开罗列,但这未免太形式化,与其记住“哪些是哪些不是”,不如真正地加以区分。伪类和伪元素本身就有一个根本的不同之处,这点直接体现在了标准的描述语句上。
先看一个伪元素 first-line
例子。现在有一段HTML,内容是一个段落:
<p>I am the bone of my sword. Steel is my body, and fire is my blood.
I have created over a thoustand blades.
Unknown to Death.Nor known to Life. Have withstood pain to create many weapon.
Yet, those hands will never hold anything. So as I pray, unlimited blade works.</p>
如果我要描述这个段落的第一行,在不用伪元素的情况下,我会怎么做?想来我一定要嵌套一层 span
,然后加上类名:
<p><span class="first-line">I am the bone of my sword. Steel is my body, and fire is my blood. </span>
I have created over a thoustand blades.
Unknown to Death.Nor known to Life. Have withstood pain to create many weapon.
Yet, those hands will never hold anything. So as I pray, unlimited blade works.</p>
再反观一个伪类 first-child
的例子,有一个简单的列表:
<ul>
<li></li>
<li></li>
</ul>
如果我要描述 ul
的第一个元素,我无须嵌套新的元素,我只须给第一个已经存在的 li
添加一个类名就可以了:
<ul>
<li class="first-child"></li>
<li></li>
</ul>
尽管,第一行和第一个元素,这两者的语意相似,但最后作用的效果却完全不同。所以,伪类和伪元素的根本区别在于:它们是否创造了新的元素(抽象)。从我们模仿其意义的角度来看,如果需要添加新元素加以标识的,就是伪元素,反之,如果只需要在既有元素上添加类别的,就是伪类。而这也是为什么,标准精确地使用 "create" 一词来解释伪元素,而使用 "classify" 一词来解释伪类的原因。一个描述的是新创建出来的“幽灵”元素,另一个则是描述已经存在的符合“幽灵”类别的元素。
伪类一开始单单只是用来表示一些元素的动态状态,典型的就是链接的各个状态(LVHA)。随后CSS2标准扩展了其概念范围,使其成为了所有逻辑上存在但在文档树中却无须标识的“幽灵”分类。
伪元素则代表了某个元素的子元素,这个子元素虽然在逻辑上存在,但却并不实际存在于文档树中。
3,伪类和伪元素分别有哪些
伪类:
CSS2及以下:
:link(锚伪类)
:visited(锚伪类)
:active(锚伪类)
:hover(锚伪类)
:focus
:first-child
:lang【p:lang(it) = 选择带有以 "it" 开头的 lang 属性值的每个 <p> 元素。
CSS3:
:first-of-type【p:first-of-type = 选择属于其父元素的首个 <p> 元素;等同于 :nth-of-type(1)。
:last-of-type
:only-of-type 【p:only-of-type = 选择属于其父元素只有<p> 元素(只能有P但可以有多个P)
:nth-of-type(n)
:nth-last-of-type(n)
:last-child
:only-child 【p:only-child = 选择属于其父元素只有唯一的子元素且为<p> 元素(只能有一个子元素且为P)
:nth-child(n)
:nth-last-child(n)【同上,但是从最后一个子元素开始计数。
:root 【选择文档的根元素。
:empty 【p:empty = 选择没有子元素的每个 <p> 元素
:target 【#news:target = 选择当前活动的 #news 元素。(突出显示活动的 HTML 锚)
:enabled
:disabled
:checked
:not(selector)
伪元素:
CSS2及以下:
:first-letter
:first-line
:before
:after
CSS3:
::selection 【使被选中的文本成为红色:::selection{color:red;}
4,伪类与CSS伪元素的典型与非典型应用
1)典型:列表处理(伪类)
a.页脚链接
页脚链接可能是一个最为合适的例子,因为例子里伪元素和伪类并用。很多网站的页脚链接是用竖线分隔的罗列<a>
标签形式。在这种页脚链接里使用伪类和伪元素的组合,就可以让链接的列表的HTML代码变得非常干净整洁:
ul.list{list-style:none;}
ul.list li{float:left;}
ul.list li:after{content:"\00a0|\00a0";}
ul.list li:last-child::after{content:"";}
但当前,放眼望去几乎不会有人这么做。绝大部分依然使用旧的方式。除了一些维护上的考量,习惯也是一个主要原因。熟优熟略这里不讨论,这里只是作为最典型的例子展示它们的应用。
b.最后项,奇偶项,倍数项
另一个广为人知的例子是:去掉列表最后一个元素的边框或者边距。在这种情况下,我们似乎已经习惯了给最后一个元素加上一个类似last-item
的类名,然后单独写一条CSS规则。
ul.list li{margin-right:10px;}
ul.list li.last-item{margin-right:0;}
实际上,我自己在写的时候也会偏向一个早就习惯了的做法。在时间限定的情况下,不会考虑激进的方案,也不会考虑类似负边距或者超界显示等等优化方案,而只是一味的寻求最为保险和熟悉的习惯上的东西。习惯是可怕的顽固,所以可能今后还是会有很长一段时间不会写成下面这样:
#ul.list li{margin-right:10px;}
#ul.list li.last-child{margin-right:0;}
隔行背景色可能是奇偶项使用最多的情况,但现在又有多少人已经完全使用odd
和even
来替代额外添加的类名?
tr:nth-child(odd){background-color:#f4f4f4;}
tr:nth-child(even){background-color:#f9f9f9;}
还有诸如 Gallery 的特定项的边距,伪类的处理也不错不是嘛?
li:nth-child(3n) {margin-right:0;}
不过眼下,似乎更多人用负边距或者inline-block
来处理,甚至直接让透明边距顶出容器,优化的手法已经很多,而且在维护性上甚至更有优势。
c.彩色
这其实还是上面的命题,但却单独拿出来说。如今的网页越来越多彩,也就不免单独指定一些亮丽的颜色。还是有很多人将特定的颜色用特定的类名标注。然而,如果颜色的映射顺序不怎么重要的话的,也许只是要达到多彩的简单目的,完全可以这么做:
li:nth-child(1) a{color:#f30;}
li:nth-child(2) a{color:#c0f;}
li:nth-child(3) a{color:#90f;}
li:nth-child(4) a{color:#06f;}
li:nth-child(5) a{color:#0cf;}
应对各种区块的色系调整,伪类的使用可以大幅减少HTML里的单一用途的类名。顺着这个例子推荐一个网站:xycss.com。这是一个由 Jeff Starr 建立的关于响应栅格布局的网站,他撰写的框架 xy.css 也有非常多的可以学习的地方。当然在这里举其作为例子还是因为这个网站的首页和这个例子相符——伪类实现的多彩的色块。
2)典型:清除浮动(伪元素)
这是一个被讲烂的命题,不过我必须将其列在伪元素的典型应用的列表里,因为一般而言,伪元素(:after)在这里总是最为常见。之前我写的《再谈清除浮动》一文已经详细阐述过,所以这里不再冗述。唯一想顺带提一下的是,虽然清除浮动方法各异,但我自己其实挺偏向空标签的,原因嘛,还是习惯吧
3)非典型:阴影
所谓的非典型应用其实无非就是“不干正经事”的意思,与当年的table
多少有些神似。这部分里有一些已经淘汰的手法,但为了纪念它们存在的痕迹,还是将它们例举和提及。
如今的浏览器大部分都已经支持box-shadow
这个方便的阴影制造器,也正因为此,box-shadow
在如今的使用中颇为频繁。关于box-shadow
的文章我也至少写过4篇:
虽然如今愈发觉得这个属性存在被滥用的危险,但是实际使用时,制造阴影往往需要和伪元素一起使用,特别是当页面中的某些布局需要额外元素制造阴影的时候。由于凡是支持box-shadow
的浏览器都支持伪元素,所以几乎任何时候要添加box-shadow
,伪元素都是考虑范围之一。比如,给全局网页加上一个顶部的阴影渐变:
body:before{content:"";position:fixed;top:-15px;left:0;width:100%;height:15px;box-shadow:0px 0px 15px rgba(150,150,150,.8);}
4)非典型:CSS调试
之前写的调试样式:debug.css,部分内容是有关 :empty
伪类的应用。
div:empty,
span:empty,
li:empty,
p:empty,
td:empty,
th:empty{padding:1em;background-color:#ff0 !important;}
:empty
可以在开发过程中以可视化的方式过滤空标签。
5)非典型:额外的提示
比如给相应的链接增加相应的内容提示:
.example-block:before {
content: "Example:";
}
在我的印象里,早期的W3c标准文档里就是类似这么干的。这种额外信息的提示源自伪元素和CSS Content的配合使用,更多例子推荐阅读 Chris Coyier写的 CSS Content
6)非典型:内描边和背景透明
这两个算是浏览器在CSS2的大时代背景里夹缝里生存的trick,如今看来早已经过时。现在的内描边可以用box-shadow
轻而易举的完成,透明背景则需要用到CSS的RGBA以及IE滤镜。但当时,不知道是谁想出用四角绝对定位一个伪元素,然后画边框来实现内描边,应用opacity和IE透明滤镜来实现背景透明。虽然过时,但每每提起这种陈年旧事总是感觉好怀念啊
5,:before与:after的用法
“伪元素”,顾名思义。它创建了一个虚假的元素,并插入到目标元素内容之前或之后。
单词“pseudo”是希腊语的英译,它的基本意思是“说谎的,不诚实的,错误的。”因此叫伪元素是适合的。因为在文档中它不实际改变什么。相反的,它们是像幽灵一般的元素插入在css中,他们对用户是可见的,可以通过css控制。
基本语法
:before 和 :after 伪元素编码非常简单(和大多数的css属性一样不需要一大堆的前缀)。这里是一个简单的例子。
这个例子中提到了两件事情,第一,我们用#example:before和#example:after来目标锁定相同的元素.严格的说,在代码中他们是伪元素。
第二,在内容模块中提到,伪元素如果没有设置“content”属性,伪元素是无用的。
在这个例子中,拥有属性id的元素将有一个哈希符号放置内容之前,和一个句号在内容之后。
语法笔记
你可以设置content属性值为空,并且仅仅把他当做一个内容很少的盒子。像这样:
然而,你不可以完全的移除content属性,如果你移除了,伪元素将不会起作用。至少,content属性需要空引用作为它的值(即:content:“”)。
你也许注意到,你也可以用两个冒号(::before 和 ::after) 写伪元素,这个我以前讨论过的。简短的解释是,对于这两种语法没有什么不同,仅仅一点的不同是,伪元素(双冒号),css3中的伪类是(单冒号)
最后就语法而言。从技术上讲,你可以普遍的应用伪元素,不是放在特殊的元素上,像这样:
虽然上面是有效的,但是它十分的没用。代码会在DOM里的每个元素的内容之前插入散列符号。即使你删除了<body>标签和它的所有内容,你仍会在页面上看见两个散列符号:一个在<html>里,另一个在<body>标签里,浏览器会自动创建哪一个。
插入内容的特点
正如前面提及的,插入的内容在页面的源码里是不可见的。只能在css里可见
同时,插入的元素在默认情况下是内联元素(或者,在html5中,在文本语义的类别里)。因此,为了给插入的元素赋予高度,填充,边距等等,你通常必须显式地定义它是一个块级元素。
这会是对如何设计伪元素的一个简要的说明,看我下面文本编辑器的这幅图
在这个例子中,我高亮的样式将被应用到元素里插入到目标元素内容的前面和后面。
还要注意的是典型的CSS继承规则适用于插入的元素。例如,你有字体系列黑体,宋体,无衬线字体应用到body元素里,然后伪元素会像其他元素一样继承这些字体系列。
同样的,伪元素不会继承没有自然继承自父元素(如 padding and margins)的样式。
之前或之后是什么?
你的直觉是:before和:after伪元素可能是 插入的内容会被注入到目标元素的前或后注入。但是,正如上面提到的,不是这样的。
注入的内容将是有关联的目标元素的子元素,但它会被置于这个元素的任何内容的“前”或“后”。
为了证明这一点,看看下面的代码。首先,在HTML:
下面是插入伪元素的css:
在此html里,你所看的一段文字带有的是一个类的box,还有这样的文字“Other content”在里面(像你所会看到的一样,如果你看见了首页的源代码)。在css中,这段内容被设置了宽度,以及一些padding和可见的边框
然后我们有了伪元素。在这个例子中,它是一个散列符号插入到该段内容之前。随后css给了它一个边框以及一些padding和margins。
这里是浏览器中查看的结果:
外面的盒子是这个段落。围绕有散列符号的边框表示伪元素的边界。所以,不是插入“before”到段落,而是伪元素被置于到此段落的“Other content”的前面。
插入非文本内容
我简要的提醒,你可以把属性的值置为空字符串或是插入文本内容。你基本上有属性的值要包含什么的两个额外的选择
首先,你可以包含一个指向一个图像的URL,就像在css里包含一个背景图像一样做你能做的
注意不能使用引号。如果你将URL用引号括起来,那么它会变成一个字符串和插入文本“url(image.jpg)”作为其内容,插入的而不是图像本身。
当然,你可以包含一个Data URI代替图像引用,正如你可以用css背景一样。
你还可以选择ATRR(X)中的函数的形式。此功能,根据规范 ,“把X属性的值以字符串的形式返回”
下面是一个例子:
attr()函数的功能是什么?它得到特定属性的值并把它作为插入的文本成为一个伪元素。
上面的代码会导致页面上的每一个<a>元素的href值立即被放置在每个各自的<a>元素的后面。在文档被打印时,它可以用作一个包含所有URl的打印样式表。
你也可以用这个函数去获取元素的title属性,或者甚至是microdata的值。当然,并不是所有的例子都符合自己的实际,但根据不同的情况,一个特定的属性值作为一个伪元素可以是实际的
然而,获取title或者图像的alt的值并作为实际的伪元素显示在页面上是不可能的。记住伪元素必须是被应用元素的子元素。图像,这是void(或者是空元素),没有子元素,所以它在这个列子中不可用,同样也适用于其他空元素,例如:<input>。
可怕的浏览器兼容性
任何前端技术的发展势头,第一个问题就是浏览器的支持。在这种情况之下,它不是个很大的问题。
浏览器支持:before 和 :after 伪元素栈,像这样:
- Chrome 2+,
- Firefox 3.5+ (3.0 had partial support),
- Safari 1.3+,
- Opera 9.2+,
- IE8+ (with some minor bugs),
- 几乎所有的移动浏览器。
唯一真正的问题是没有获得支持的(不用奇怪)IE6和IE7。所以,如果你的爱好者是在良好合适的web开发(或者其他具有较低IE版本的市场),你可以继续*地使用伪元素。
伪元素不是决定性的
幸运的是,缺少伪元素不会造成大问题。大多数情况下,伪元素一般修饰(或者帮助)内容,不会给不支持的浏览器造成问题。所以,如果你的支持者具有较高的IE版本,你仍然可以在某种程度上使用它们。
一些提醒
正如前面提到的,伪元素不会出现在DOM中。这些元素不是真正的元素。因此,它们不是可用的。所以,不要使用伪元素生成内容,是您的网页的可用性和可访问性的关键。
另外一件需要记住的是,开发工具,例如火狐,不要用伪元素显示内容。所以,如果使用了,伪元素会造成难以维护和调试缓慢。
(更新:在评论中提到的,你可以使用谷歌的开发工具来查看一个伪元素相关联的风格,但不会出现在DOM元素里。同时,火狐在1.8版加入伪元素支持它。)
from 阿桃(http://blog.csdn.net/taotao6039) 整理自以下文章:
http://swordair.com/origin-and-difference-between-css-pseudo-classes-and-pseudo-elements/
http://swordair.com/typical-and-atypical-usage-of-css-pseudo-classes-and-pseudo-elements/
http://www.w3cplus.com/css3/learning-to-use-the-before-and-after-pseudo-elements-in-css.html