CSS3伪类与伪元素的区别及注意事项
原文出处:尐轩web前端网络日志
CSS中伪类与伪元素的概念是很容易混淆的
今天就来谈谈伪类与伪元素之间的区别
定义
首先先来看看伪类与伪元素的定义
w3c中对于它们是这么解释的
- 伪类:用于向某些选择器添加特殊的效果
- 伪元素:用于将特殊的效果添加到某些选择器
讲道理,可能我语文不好,我觉得这两句话是等价的 😃
根本不能看出有什么区别
都是对某些选择器“加特技”
标准有这么一句话翻译过来是这样的
CSS 引入伪类和伪元素的概念是为了实现基于文档树之外的信息的格式化
这话更抽象,其实意思就是对那些我们不能通过class、id等选择元素的补充
区别
这个区别我们需要一个例子来理解
<p>
<em>This</em>
<em>is a text</em>
</p>
如果我们想要第一个em标签字体颜色变红怎么做呢
使用我们熟悉的伪类很简单
em:first-child {
color: red;
}
但是如果不存在伪类我们怎么做呢
这是我们就需要为第一个em标签添加类
This is a text
<p>
<em class="first-child">This</em>
<em>is a text</em>
</p>
em.first-child {
color: red;
}
可以实现同样的效果
<p>
<em>This</em>
<em>is a text</em>
</p>
还是这个例子
现在我想让这个段落的第一个字母变红
怎么做呢
这回我们需要使用伪元素
p::first-letter {
color: red;
}
同样假设伪元素不存在的情况
这时我们只能嵌套span标签来实现
This is a text
<p>
<em><span>T</span>his</em>
<em>is a text</em>
</p>
p span {
color: red;
}
看到这里,相信大家已经清楚了为什么一个叫做伪类,一个叫做伪元素
伪类的效果可以通过添加实际的类来实现
伪元素的效果可以通过添加实际的元素来实现
它们的本质区别就是是否抽象创造了新元素
历史
伪类最开始的时候只是用来表示元素的动态(典型的锚伪类link、visited、hover、active)
在CSS2标准中对它进行了扩展让它虽然逻辑存在但不需要在DOM树中标识
伪元素代表了某个元素的子元素,虽然逻辑存在,但不存在于DOM树
虽然它们的概念很容易被我们混淆
但是也不影响我们正常使用
我在 CSS3选择器介绍及用法总结 中说过
伪类只能使用“:”
而伪元素既可以使用“:”,也可以使用“::”
这里我就解释一下为什么
CSS3中的标准是伪类使用单冒号“:”
而伪元素使用双冒号“::”(避免混淆)
但是在此之前无论是伪类还是伪元素都使用单冒号“:”
所以为了保证兼容伪元素两种使用方法都是可以的
但是低版本IE有双冒号兼容问题
所以以前编写样式的人们对于伪类和伪元素就干脆统统使用单冒号
导致这种混淆一直延续下来
注意
在使用伪类和伪元素的时候
有一点要特别注意
伪类就像真正的类一样,可以叠加使用
没有数量上限,只要不是互斥的
比如这样
em:first-child:hover {
color: red;
}
这是完全可以的
但注意,这里是“与”的关系
也就是说既要满足“first-child”第一个子元素
又要满足“hover”光标悬浮
伪元素就要严格的多
伪元素在一个选择器中只能出现一次,并且只能出现在末尾
(这里有同学误会了,所以我作出了修改)
像下面的样式是无法生效的
p::first-letter:hover { /*错误的写法:伪元素不是末尾*/
color: red;
}
p::first-letter::selection { /*错误的写法:伪元素出现了多个*/
color: red;
}
再多说一句关于它们的优先级
在计算权重的时候
伪类与类优先级相同
伪元素与标签优先级相同
总结
1.伪类与伪元素都是用于向选择器加特殊效果
2.伪类与伪元素的本质区别就是是否抽象创造了新元素
伪类只要不是互斥可以叠加使用
3.伪元素在一个选择器中只能出现一次,并且只能出现在末尾
4.伪类与伪元素优先级分别与类、标签优先级相同
5.img、input和其他的单标签是没有after和before伪元素的,因为单标签本身不能有子元素
伪元素的案例
一、伪元素:before和:after用法
这个两个伪元素在真正页面元素内部之前和之后添加新内容(当然了,可以对伪元素应用定位可以置于任何位置)。可以用以下例子来说明:
<p>wonyun!</p>
<style>
p:before{content: "hello "}
p:after{content: "you are handsome!"}
</style>
上面例子从技术角度看,等价于下面的html结构:
<p>
<span>hello </span>
wonyun!
<span> you are handsome!</span>
</p>
content
由此可知:伪元素:before和:after添加的内容默认是inline元素;这个两个伪元素的content属性,表示伪元素的内容,设置:before和:after时必须设置其content属性,否则伪元素就不起作用。那么问题来了,content属性的值可以有哪些内容呢,具体有以下几种情况:
字符串,字符串作为伪元素的内容添加到主元素中
注意:字符串中若有html字符串,添加到主元素后不会进行html转义,也不会转化为真正的html内容显示,而是会原样输出
attr(attr_name),
attr(attr_name), 伪元素的内容跟主元素的某个属性值进行关联,及其内容为主元素的某指定属性的值
好处:可以通过js动态改变主元素的指定属性值,这时伪元素的内容也会跟着改变,可以实现某些特殊效果,如图片加载失败用一段文字替换。
url()/uri()
url()/uri(), 引用外部资源,例如图片;
counter()
counter(), 调用计数器,可以不使用列表元素实现序号问题。
二、:before和:after特点
:before和:after伪元素的主要特点如下:
1.伪元素不属于文档,所以js无法操作它
2.伪元素属于主元素的一部分,因此点击伪元素触发的是主元素的click事件
3.原文说块级元素才能有:before, :after,其实是不妥的,大部分行级元素也可以设置伪元素,但是像img可替换元素,因为其外观和尺寸有外部资源决定,那么如果外部资源正确加载,就会替换掉其内部内容,这时伪元素也会被替换掉,但是当外部资源加载失败时,设置的伪元素是可以起作用的。
基于伪元素的特点可以知道其优缺点,也引用别人文章的话:
优点
减少dom节点数
让css帮助解决部分js问题,让问题变得简单
缺点
不利于SEO
无法审查元素,不利于调试
三、:before和:after常见使用场景
1.清除浮动
清除浮动
清除浮动是前端最常见的问题,有一种做法是使用一个空的页面元素如div来清除浮动,但是这种做法增加毫无语义的页面元素,而且占用dom节点。更可取的做法是利用伪元素来清除浮动:
<div class="l-form-row">
<div class="l-form-label"></div>
....
</div>
<style>
.l-form-row:after {
clear: both;
content: "\0020";
display: block;
height: 0;
overflow: hidden
}
</style>
这样,class=l-form-row的元素内部任何浮动都能清除掉,不用额外添加无意义的元素。
利用attr()来加载图片失败
利用attr()来实现某些动态功能
在页面中常见这种问题,页面上加载的图片在无法加载时会显示一个破损图片,直接影响页面的美观;
那么可以通过伪元素配合样式能够让未加载的图片看起来真的像破裂的效果,如下图所示:
是一个替换元素,其外观和尺寸是由外部资源来决定的,当外部图片资源加载失败时其会显示破裂图片和alt文字,尺寸仅由其自身内容决定。这时元素可以使用伪元素:before和:after,因为其元素内容没有被替换;利用attr()来获取图片alt属性值作为伪元素:after的content内容来替换img的内容,并运用适当的样式从而完成:图片加载成功时显示正常的图片,加载失败时显示图片破裂效果的样式,具体代码参考:
<!-- 图片加载失败时的显示问题 attr()-->
<div>
<img src="xxx.gif" alt="lululu">
</div>
div {
width: 100px;
height: 100px;
overflow: hidden;
}
img {
display: inline-block;
width: 100%;
height: 100%;
position: relative;
}
img::after {
content: attr(alt);/* 生成 alt 信息 */
position: absolute; left: 0;bottom: 0;right: 0;
background-color: rgba(0,0,0,.5);
transform: translateY(100%);/* alt 信息隐藏 */
transition: transform .2s;/* 过渡动画效果 */
}
img:hover::after {
transform: translateY(0);/* alt 信息显示 */
}
counter()用来计数
与counter()结合实现序号问题,而不用使用列表元素。具体还要结合css的 counter-increment 和 counter-reset 属性的用法 。
代码如下:
结果如下:
特效使用
利用这两个伪元素,可以实现各种效果,如放大镜、叉叉、箭头、三角符等,也可轻易实现如下效果
代码实现如下:
a {
position: relative;
display: inline-block;
outline: none;
text-decoration: none;
color: #000;
font-size: 32px;
padding: 5px 10px;
}
a:hover::before, a:hover::after { position: absolute; }
a:hover::before { content: "\5B"; left: -20px; }
a:hover::after { content: "\5D"; right: -20px; }
代码实现如下:
table{overflow: hidden;}
td, th{
padding: 10px;
position: relative;
outline: 0;
}
td:hover::after,
th:hover::after {
content: '';
background-color: lightblue;
position: absolute;
left: 0;
height: 10000px;
top: -5000px;
width: 100%;
z-index: -1;
}
td:hover::before {
background-color: lightblue;
content: '';
height: 100%;
top: 0;
left: -5000px;
position: absolute;
width: 10000px;
z-index: -1;
}
具体代码:
.empty__bg {
display: inline-block;
width: 95px;
height: 92px;
background: url(http://7tszky.com1.z0.glb.clouddn.com/FvD_sYY4Fmp_yKS0E07H-5jhuKTB) no-repeat;
background-size: 95px 92px;
position: relative;
margin-bottom: 16px;/*注意这里需要留好位置放置after元素(它是absolute进去的)*/
}
.empty__bg:after {
content: "暂无学习计划";
display: block;
font-size: 14px;
line-height: 24px;
text-align: center;
width: 100%;
color: #909090;
position: absolute;
top: 100%;
left: 0;
}
}
上述可以实现扩大可点击区域,这对应手机用户来说更加友好一些,否则用户点击不会触发相应的事件;具体代码实现如下:
.play-cover {position: relative}
.play-cover:before{
content: "";
display: block;
position: absolute;
width: 0;
height: 0;
border-left: 8px solid white;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
margin-left: 9px;
margin-bottom: 7px;
z-index: 5;
}
.play-cover:after{
content: '';
display: block;
position: absolute;
width: 20px;
height: 20px;
border: 2px solid white;
background: rgba(0, 0, 0, .6);
border-radius: 12px;
background-clip: padding-box;
}
CSS美化radio和checkbox的样式magic-check,就是利用伪元素:before和:after来实现的;
具体是为每个真正的表单元素radio和checkbox搭配一个label,然后隐藏真正的radio和checkbox,label元素单击的时候隐藏的radio或者checkbox实际上是处于checked状态,这跟label的具体用法有关;利用label的伪元素:before和:after来实现美化radio和checkbox。
下面是checkbox的美化的css代码:
.magic-checkbox {
position: absolute;
display: none; //先隐藏真正的checkboxbox
}
.magic-checkbox + label {//为与checkbox搭配的label使用样式
position: relative; //相对定位,方便其内容的伪元素进行定位
display: block; //块元素
padding-left: 30px;
cursor: pointer;
vertical-align: middle;
}
.magic-checkbox + label:before { //label添加:before伪元素,用于生成一个带边界的正方形,模拟复选框的轮廓
position: absolute;
top: 0;
left: 0;
display: inline-block;
width: 20px;
height: 20px;
content: '';
border: 1px solid #c0c0c0;
border-radius: 3px;
}
//为checkbox添加:after伪元素,作用是生成一个√图形,模拟checkbox选中状态,未选中状态下会被隐藏
.magic-checkbox + label:after {
top: 2px;
left: 7px;
box-sizing: border-box;
width: 6px; //实现√图形很简单:设置一个长方形,去掉其上边界和左边界,剩下的2个边界旋转45度就得到√形状
height: 12px;
transform: rotate(45deg);
border-width: 2px;
border-style: solid;
border-color: #fff;
border-top: 0;
border-left: 0;
position: absolute;
display: none; //√形状先隐藏
content: '';
}
//单击label,隐藏的checkbox为checked状态,这时设置checked状态下搭配label的:before伪元素背景和边界颜色
.magic-checkbox:checked + label:before {
animation-name: none;
border: #3e97eb;
background: #3e97eb;
}
//checked状态的checkbox搭配的label伪元素:after此时设置显示,那么√就显示出来了
.magic-checkbox:checked + label:after {
display: block;
}
利用:before和:after能轻易实现美化的radio和checkbox