伪元素已经不是什么新东东了,大家在实际生产中肯定有使用过伪元素。但伪元素能帮助我们做些什么呢?针对该问题,有很多同学能很好的回答,但也有很多场景并不是所有开发人员都完全了解的。今天再次花时间来整理一下伪元素能帮助我们做些什么?我想接下来的内容和实例肯定会有不少同学感兴趣的。如果你是其中的一位,那么请继续往下阅读。
伪元素是什么
元素事实上是HTML中的概念,常常把HTML中的标签称作为元素。那么伪元素是什么呢?从其名称上来说,伪即为假,在实际的DOM中是不存在的,而事实上呢?我们可以借助一些CSS的特性让其模拟成一个元素,对于这样的元素我们称之为伪元素。
在W3C的标准规范中也有独立的规范文档,时到今日,伪元素的最新规范是 CSS Pseudo-Elements Module Level 4。在该规范中有我们熟悉的伪元素,比如::first-line
、::first-letter
、::selection
、::placholder
、::after
和::before
,也有我们不熟悉的::marker
、::inactive-selection
、::spelling-error
和::grammar-error
。
不过我们今天要聊的仅仅是其中的::before
和::after
两个伪元素。这两个伪元素配合W3C的另外一个规范 CSS Generated Content Module Level 3 中的content
可以创建出两个伪元素。这样一来,一个HTML元素就具备多个盒模型,即有多个背景和边框等,正如下图所示:
伪元素如何生成内容
刚才提到过,伪元素::before
和::after
需要和CSS的content
结合在一起才能有效的生成内容或盒子。比如:
1 | HTML复制代码<!-- HTML --> |
1 | CSS复制代码div{ |
在浏览器中查看元素时,可以看到::before
插入到div
内容前面,::after
插入到div
内容后面,如下图所示:
再次强调,::before
和::after
能生效是因为我们在伪元素中显式的声明了content
,哪怕是个空字符串。虽content
是一个空字符串值,但这个时候其实已经在页面中就生成了一个盒模型,而且也具备了“Computed”的样式,如下图所示:
这个时候适用于元素的CSS属性也就适用于伪元素上了。比如:
1 | CSS复制代码div { |
效果如下:
如果在::before
和::after
中未显式设置content
的话,那么就无法将伪元素插入到DOM结构中,如下所示:
上面我们看到的是给content
一个空字符串,事实上除了空字符串还可以是任意你想要的字符串,比如文本,HTML实体符,Emoji等。比如:
除此之外,还可以配合content
的其他特性来生成内容,比如attr()
函数将HTML标签的属性值当作伪元素的内容,还可以通过url()
函数将图片当作伪元素内容:
1 | HTML复制代码<div data-content="Let's Go!">我是一个div</div> |
1 | CSS复制代码div::before { |
更为厉害的是,还可以将attr()
、url()
与字符串内容结合起来使用:
1 | CSS复制代码div::before { |
还可以更复杂一些,将他们都结合在一起:
1 | CSS复制代码div::before { |
content
除了上面所提到的特性之外,还可以配合counters
、counter-increment
和counter-reset
实现自动计数器和列表编号等,但该效果暂时先不阐述,我们将放到后面来聊这个特性。
接下来我们来看看在实际上能帮助我们做些什么?
伪元素的常见用例
我们先来看看伪元素相关的常见用例。
清除浮动
CSS的float
属性虽然其本质不是用来布局的,但很长一段时间中它都被用于Web布局中。熟悉float
的同学都知道,浮动会带来一些其他的麻烦事情,比如说容器高度的坍塌。也正因为这些原因,在使用float
时,最好记得清除浮动。其中清除浮动有一种经典的用法clearfix
,它就是借助伪元素来完成:
1 | CSS复制代码.clearfix:before, |
Icon图标
随着CSS的@font-face
的出,伪元素常被用于一些Icon Font中,用来制作Icon图标。在业内很多Icon Font库都采用这种方式来实现的,比如著名的 Font Awesome。
1 | CSS复制代码.fa-flag:before { |
另外在一些纯CSS绘制的Icons上也有伪元素的身影,比如@wentin的CSS Icons库中的很多标有借助了伪元素:
1 | HTML复制代码<div class="audio-solid icon"></div> |
1 | CSS复制代码.audio-solid.icon { |
伪元素和Sprites的结合
在Web开发中,时常会用到CSS Sprites或者是SVG Sprites来节约请求。那么在使用Sprites时为了更好的控制图标的容器,常常是通过增加一个额外的标签或者伪元素。比如:
Demo 地址:codepen.io/airen/full/…
上面的示例每个button
的文本前面有一个Icon图标,示例中的每个图标的尺寸大致是32px x 32px
,使用伪元素::before
来起到一个空标签作用,从而更好的更控制图标容器大小,位置。
制作Ribbon和Bubbles
红丝带(Ribbon)和气泡(Bubbles)时常都是通过纯CSS绘制而成,比如气泡效果。早在2010年@necolas就用纯CSS实现了不同效果的气泡,而这些气泡效果都有使用到伪元素:
和气泡类似,结合伪元素可以实现不同效果的丝带,比如下面这个效果:
Demo 地址:codepen.io/nikhil/full…
如果你足够仔细的话,你会发现,这个和前面绘制图标的案例有点类似。的确是这样的,特别是在一个div
绘制不同图形的案例,更显伪元素的强大:
是不是觉得不可思议,要是你也想尝试着使用一个div
绘制出一个图形(你喜欢的图形),其思路和具体操作步骤可以参阅读@Lynn Fisher和Robert Nyman一起写的一篇教程《Single Div Drawings with CSS》。
而且在Codepen上你搜索“Single Div”,你会发现有很多优秀的案例,足可以让你脑洞大开:
告诉你一个更有意思的网站,那就是**CSSBattle**,这是一个况技网站,用最少的代码实现同一个效果,谁的代码量少谁就获胜。这里面的效果基本上是基于一个
div
完成的。可以说是一个练习CSS绝佳场所。
CSS Divider(分隔线)
在实际生产中会碰到区块之间的分隔线,常常我们把其称为CSS Divider,如下图所示:
面对这样的效果,在内容前后插入伪元素是非常有效的,比如下面这样的一个示例:
1 | CSS复制代码div { |
你看到的效果如下:
Demo 地址:codepen.io/airen/full/…
上面的效果是最简单的,你可以根据自己所需要的效果,让其更个性化:
Demo 地址:codepen.io/airen/full/…
@Samia Rai在《25 Creative CSS Divider Examples》一文中收集了共25
种有关于CSS制作的分隔线案例,当然有些是没有使用到伪元素的。如果你感兴趣的话,你可针对同样的效果,做一些改造。
CSS Tooltips
提示框(Tooltips)对于大家而言应该不会感到陌生。在实际制作提示框效果时,使用纯CSS也可以很好的实现。特别是配合HTM标签自定义属性会显得更为有意思。在介绍伪元素如何生成内容的时候,我们提到过content
配合HTML标签自定义属性的时候,可以让自定义属性的值很好的放到伪元素中。
也就是说,基于该特性,我们可以很好的实现提示框的效果。比如:
1 | HTML复制代码<span class="tool" data-tip="By adding this class you can provide almost any element with a tool tip." tabindex="1">tool</span> |
1 | CSS复制代码.tool { |
效果如下:
Demo 地址:codepen.io/airen/full/…
自动生成计数器
如果给一个列表添加列表项目,如果是一个默认效果的话,可能会直接考虑ol
这样的有序列表,但很多时候我们是需要一些个性化的列表项目符:
不考虑别的,原生CSS就具备这方面的特性。不知道大家是否还记得,我们在前面给大家预留了一个话题:伪元素结合content中的counters、counter-increment和counter-reset实现自动计数器和列表编号。
其原理很简单:
配合不同的CSS我们可以实现很多个性化的效果:
这里要提一下我的偶像 @Ana Tudor,她给大家提供的案例更是令我们感到CSS强大的魅力。比如她的博文《Restricting a (pseudo) element to its parent’s border-box》中的案例:
Demo 地址:codepen.io/thebabydino…
虽然它们的结合能让我实现很多个性化的列表项的效果,但这里我要告诉大家的是,在未来CSS的::marker
能赋予我们更强的能力,如果对该特性感兴趣的话,可以阅读《聊聊CSS的::marker 》一文。
CSS Loading Animation
CSS的伪元素事实上就是一种免费的DOM元素,DOM元素具备的很多特性它们也同样具备。CSS的样式也是如此。比如我们常常在加载页面时用到的Loading动效,就有很多是借助CSS的伪元素一起完成的,比如@Camden Foucht写的LoadLab就是一个很好的示例:
Demo 地址:codepen.io/camdenfouch…
如果你对Web动效方面感兴趣的话,可以点击这里查看有关于这方面的教程。
优化链接
在Web页面中,你的链接会有站内链接也会有站外链接,可以通过伪元素很好的告诉你的用户它们之间的区别。比如下面这个示例:
1 | CSS复制代码a[href^="http"]:hover::after{ |
效果如下:
Demo 地址:codepen.io/airen/full/…
类似的思路也可以用于其他的一些链接或导航菜单上(当然也可以用于你自己喜欢的任何地方):
Demo 地址:codepen.io/sincamons/f…
如果你的链接是链接了一些文件(提供给用户下载或在线阅读),那么可以配合CSS属性选择器,根据文件扩展名提供不同的Icon图标向用户示意:
Demo 地址:codepen.io/airen/full/…
Switch Toggle Button (切换按钮)
自定义的checkbox
和radio
(也常称作Switch Toggle),通过label
标签和其伪元素,可以轻易实现个性化定制效果,比如下面这个示例:
Demo 地址:codepen.io/fabriceleje…
上面列举了十种我们使用伪元素常见的场景,当然还有很多场景没有可能被我遗漏了,如果你有这方面的经验和案例,欢迎在下面的评论是与我们一起分享。
伪元素的不常见用例
接下来,我们再来看一些伪元素不见常的用例和使用场景。
盒阴影
在CSS中虽然有box-shadow
和drop-shadow()
可以让我们给一个元素添加阴影效果。但有些场景,他们是心有余而力不足的。比如:
针对于这样的场景我们使用伪元素可以让事情变得简单地多:
Demo 地址:codepen.io/airen/full/…
上面这个模拟3D按钮的算是简单了。采用同样的技术,也可以很好的实现上图所示的侧边,中间等不位置的阴影效果:
Demo 地址:codepen.io/jcorpus/ful…
这样做是有一定原因的。将box-shadow
转换为伪元素实现阴影效果,对于性能是较大帮助的。特别是有动效的地方,可以让阴影效果更为平滑:
如果你使用浏览器开发者工具查看的话,两个效果之间的渲染的差异有多大:
链接和图片的连动
这个效果的思路很奇特,在伪元素上使用图片,而且伪元素和链接能相互连动。这个效果是来自于@Ahmad Shadeed的《Uncommon Use Cases For Pseudo Elements》一文。先上Demo吧:
Demo 地址:codepen.io/shadeed/ful…
代码并不复杂,主要是思路新奇:
1 | CSS复制代码.link-1 { |
尝试着在上面的示例中,将鼠标悬浮到链接上或者右侧颜色的区域上,你都可以看到两者有连动效果:
想象一下,如果将示例中的颜色区域换成产品图片,是不是很有创意:
扩展可点击区域
可点击区域是不合理直接影响了用户和你的产品的交互,特别是在移动端。大家可能有碰到过,有些产品在按钮、链接、复选框或单选框等操作上就是失效,要点击很多次才能有效果。造成这种行为就是因为点击区域过小。
特别是在一些带可点击操作的图标上,Icon图标的实际尺寸并不适合一些系统的设计规范,在iOS上就提供Icon图标可点击区域应该是48px x 48px
,如果你使用的图标小于该区域的话,我们就应该通过别的方式来进行扩展。那么伪元素是一个较好的方式。比如下面这个示例:
Demo 地址:codepen.io/shadeed/ful…
@Ahmad Shadeed 和 @hankchizljaw 有过一个共同的观点。比如在一个卡片上,可以让整个卡片都具有可点击效应(click
事件绑定在button
或一个<a>
)元素之上。如下图所示:
也可以查看下面的Demo源码:
Demo 地址:codepen.io/airen/full/…
蒙层效果
大家是否还记得在《CSS 的 Clipping 和 Masking》一文中介绍Masking和Clipping技术时,先用常规则的CSS技术实现了缕空的效果:
Demo 地址:codepen.io/airen/full/…
正如你所看到的,不管是使用box-shadow
、border
还是radial-gradient()
都没有离开伪元素的身影。在某些场景之下,如果要给元素上面添加一层,借用伪元素的确是一个较好的选择。特别是想对图片做一些特殊效果的时候:
Demo 地址:codepen.io/airen/full/…
除了这种简易效果之外,还可以实现交叉布局效果:
Demo 地址: codepen.io/airen/full/…
以及一些淡入淡出的效果:
Demo 地址:codepen.io/airen/full/…
Slider 和 Output
@Ana Tudor在《Using Conic Gradients and CSS Variables to Create a Doughnut Chart Output for a Range Input》一文介绍了怎么使用input[type="range"]
实现一个圆形进度条。这也是个很有意思的案例,而且涉及到知识点较多,效果中运用到伪元素只是其中小小的一部分,感兴趣的同学可以阅读教程和示例源码:
Demo 地址:codepen.io/airen/full/…
不一样的计数器
伪元素和content
结合是可以做很多事情。正如前面所示,结合content
中的counters
、counter-increment
和counter-reset
实现自动计数器和列表编号等。除此之外,配合CSS自定义属性,还可以实现另样的效果,比如下面这个递增(递减)的案例:
Demo 地址:codepen.io/airen/full/…
有关于伪元素不常见的用例就整到这个为止。@Ahmad Shadeed在他的博文《Uncommon Use Cases For Pseudo Elements》还提供了一些其他的案例,感兴趣的可以去看看。如果你有其新奇或有意思的案例,欢迎与我们一起共享。
小结
CSS伪元素并不是什么新知识点或者说新技能,在这篇文章中主要是搜集和整理了自己在以往项目中用到的案例(或将来可用)。说实话并没有太多的隐藏技能,只不过有些案例可以开拓我们的思路,打开我们的眼界。最后希望这篇文章对你有所帮助。
如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程:
本文转载自: 掘金