伪元素的各种骚操作
前言
很早之前阅读大佬优秀的CSS源码的时候,总会看到一些::before,::after这样的代码,但是自己日常中却很少用到,最近在实际工作中,发现这两种伪元素能够带来很大的便利,于是找了个时间来深入理解一下这两种伪元素。
定义
CSS中有一类元素称作“伪元素”,例如::first-letter,::first-line,::before,::after,::selection,但是常用像::before,::afte能给我们在书写样式的时候带来很多便利,那么为什么他们会被称为伪元素呢?因为这些伪元素并不会出现在dom中,也就是说它们只是在CSS渲染层面上的东西,相比于普通元素,伪元素是无法用js获取到的,它们不会改变文档内容,不可复制,只是用于在css渲染中向元素逻辑上的头部或尾部添加内容。今天我们开始探索其中两种伪元素::before,::after的用法,因为它们在一些场景能带来极大的便利。
例子
我们以两个简单的例子来说描述这俩个伪元素
给书名加个书名号
这是一个很实用的例子,假如后端返回的数据没有给你加上书名号,需要在前端来加,用js来操作显然对性能不友好,不过用伪元素就能很完美地解决这个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <style> .direc::before{ content: "《" } .direc::after{ content: "》" } </style>
<body> <p class="direc">西游记</p> <p class="direc">基督山伯爵</p> <p class="direc">红与黑</p> <p class="direc">你不知道的JavaScript</p> </body>
|
如图:

给手机号码加个电话符号
这个在实际当中也很常见,我们经常在一些网页地footer下面看到联系方式会带上这个符号:
1 2 3 4 5 6 7 8 9 10
| <style> .tel::before { content: '\260E'; color: skyblue; } </style>
<body> <span class="tel">13082801882</span> </body>
|
如图:

探究伪元素的display属性
那么我们问题来了,我们上面用到的伪元素既然是元素,那么是属于什么元素呢?我们来看看chorme调试工具下它的display属性是什么:

我们看到,伪元素的默认display属性是inline,那么,我们可以自定义伪元素的display吗?我们看下面代码:
1 2 3 4 5 6 7 8 9 10 11
| <style> .tel::before { content: '\260E'; color: skyblue; margin: 30px; display: block; } </style> <body> <span class="tel">13082801882</span> </body>
|
我们将伪元素设置为block,并且设置他的margin(因为inline元素的margin-top与margin-bottom是不生效的),我们看看是什么效果:

如图所示,可以表明伪元素虽然不是dom中真正的元素,但是和普通元素有一样的CSS样式效果,那么我们就能用它来做很多事~
伪元素是否脱离文档流
那么问题来了,之前我们说过伪元素和普通呀孙元素有很大的区别,最明显的就是伪元素不会出现在DOM中,不会改变文档内容,不可复制,仅仅是在css渲染层加入,那么我们来探究它是否会脱离文档流,是否对其他元素的排布会有影响:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <style> .box1{ display: inline-block; height: 100px; width: 50px; border: 1px solid red; } .box1::before { content: ''; display: block; height: 30px; width: 100px; background: pink; } .box2{ display: inline-block; height: 100px; width: 50px; border: 1px solid green; } </style> <body> <div class="box1"></div> <div class="box2"></div> </body>
|
如图:

我们试图将伪元素来挡住box2的布局,但是效果确实box2的布局丝毫不影响,并且box2的z-index要大于伪元素,因此伪元素是脱离文档流的,并且z-index的值也非常低。
弄清楚上面几个属性后,我们开始真正地去探究伪元素能给我们带来什么~
content属性
这是一个非常非常容易被忽视的属性,很多小伙伴在使用伪元素的时候都容易犯错:“为啥我的伪元素没有显示出来?”,最后一查才发现,是自己的content属性没有设置,导致伪元素不显示,那么content元素究竟可以填哪些东西呢?
string
最简单的不过如此,上面例子1中给书名添加书名号的就是string类型
attr()
嗯哼,这是什么值,难不成还能设置元素的attr?我们来一串代码解释一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <style> .test1::after { content: attr(class) } .test2::after { content: attr(href) } </style>
<body> <span class="test1">this el's class is :</span> <br> <a class="test2" href="baidu.com">百度:</a> </body>
|
如图:

非常好理解,就是在元素后面加上该元素的属性值。
url()
这个属性是用来索引媒体文件,比如一个放一个图片,经过测试,对mp4、pdf、mp3格式的文件并不能显示出来:
1 2 3 4 5 6 7 8 9
| <style> .test1::before { content: url("https://sfault-avatar.b0.upaiyun.com/124/827/1248273836-57c7f5f15344a_big64"); } </style>
<body> <span class="test1">there is a pic before the el</span> </body>
|
如图:
counter()
CSS中有个计数器属性,就能能够像一个树状图一样列出1.1 1.2这样的目录结构,对于这个属性,后续我也会专门出一篇博文来总结它的使用方式。对于伪元素来说,能定制计数器的分隔符号,说的有点抽象,我们来个demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <style> body{ counter-reset: section; } h1{ counter-reset: subsection; } h1:before{ counter-increment:section; content:counter(section) "、"; } h2:before{ counter-increment:subsection; content: counter(section) "-" counter(subsection) "、"; } </style>
<body> <h1>CSS的世界</h1> <h2>color</h2> <h2>fonst-size</h2> <h2>backgroung</h2> <h1>HTML的世界</h1> <h2>div</h2> <h2>ul</h2> <h1>Javascript的世界</h1> <h2>原型</h2> <h2>闭包</h2> </body>
|
如图:

也就是说能够定制每个分隔的符号,计数器属性非常好用,就像之前之前给书名加上书名号的那个例子一样,以防后端不给你序列号~
常见用法
清除浮动
包括我,对于伪元素的认知在之前还是处在清除浮动这个作用上,anyway,这也是一个很不错的用法,尽管当初CSS设置伪元素并不是为了清除浮动,设置浮动也并不是用来css实现拼方块一样布局,但是CSS就是这么神奇,多个属性结合在一起,就能做出很多有趣的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <style> .cf:before, .cf:after { content: " "; display: table; }
.cf:after { clear: both; }
.cf { *zoom: 1; } .box { border: 1px solid red; } .smbox { float: left; width: 30px; height: 30px; background: pink; } </style>
<body> <div class="box cf"> <div class="smbox"></div> </div> </body>
|
如图:

实现各种有趣的图形
我们来实现一个六边形
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <style> .star{ width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 100px solid red; border-top: 50px solid transparent; position: relative; } .star::after { content: ''; width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-top: 100px solid red; border-bottom: 50px solid transparent; position: absolute; top: 30px; left: -50px; } </style>
<body> <div class="star"></div> </body>
|
如图:

其实就是用伪元素制造一个三角形,然后与原元素合成为一个六角星。
实现一些有趣的小icon
利用beofre和after两种伪元素,合成一些简单的icon,这样我们就不需要再去获取图片的icon,一下的icon实现来自其他小伙伴的分享:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <style> #wraper{padding:10px;width:380px;height:380px;border:3px solid #ccc;margin:auto;} #power{width: 30px;height: 30px;margin:20px;border: 6px solid #EEB422;border-radius: 50%;position: relative;display: inline-block;} #power:before{width:7px;height:22px;background:#EEB422;position: absolute;left:8px;top:-13px;content: "";border: 3px solid #fff;} #play{width: 30px;height: 30px;margin:20px;border: 6px solid #EEB422;border-radius: 50%;position:relative;display: inline-block;background: #EEB422;} #play:before{border:11px solid transparent;border-left:17px solid #fff;content: "";position: absolute;left:9px;top: 3px;} #pause{width: 30px;height: 30px;margin:20px;border: 6px solid #EEB422;border-radius: 50%;position:relative;display: inline-block;background: #EEB422;} #pause:before{height:20px;width:5px;border:0px solid transparent;border-left:8px solid #fff;border-right:8px solid #fff;content: "";position: absolute;left:4px;top: 5px;} #stop{width: 30px;height: 30px;margin:20px;border: 6px solid #EEB422;border-radius: 50%;position:relative;display: inline-block;background: #EEB422;} #stop:before{height:17px;width:17px;background:#fff;content: "";position: absolute;left:6px;top: 6px;} #comment{width: 50px;height: 25px;margin:20px;border: 6px solid #EEB422;border-radius: 20%;position:relative;display: inline-block;background: #EEB422;} #comment:before{border:10px solid transparent;border-top:10px solid #EEB422;content: "";position: absolute;left:28px;top: 28px;} #comment:after{content: "....";position: absolute;color: #fff;font-size: 26px;top: -10px;left: 2px;} #like{width: 50px;height: 30px;margin:20px;border-radius: 55%;transform:rotate(55deg);-webkit-transform:rotate(55deg);position:relative;display: inline-block;background: #EEB422;} #like:before{width:50px;height:30px;border-radius: 55%;transform:rotate(-110deg);-webkit-transform:rotate(-110deg);background:#EEB422;content: "";position: absolute;left:8px;top: -12px;} #search{width: 20px;height: 20px;border:4px solid #EEB422;border-radius:50%;margin:20px;position:relative;display: inline-block;top: -5px;left: -5px;} #search:before{width:20px;height:5px;background:#EEB422;transform:rotate(45deg);-webkit-transform:rotate(45deg);content: "";position: absolute;left:15px;top: 22px;} #home{width: 30px;height: 30px;background:#EEB422;margin:20px;position:relative;display: inline-block;top: 5px;} #home:before{width:6px;height:12px;background:#fff;content: "";position: absolute;left:12px;top: 20px;} #home:after{border:25px solid transparent;border-bottom:20px solid #EEB422;content: "";position: absolute;top: -38px;left:-10px;} #photo{width:40px;height:30px;background:#EEB422;margin:20px;position:relative;display: inline-block;top: 5px;} #photo:before{width:13px;height:13px;border:4px solid #fff;border-radius:50%;background:#EEB422;content: "";position: absolute;left:10px;top: 5px;} #photo:after{width:15px;height:10px;background:#EEB422;content: "";position: absolute;top: -7px;left:13px;} #photo{width:40px;height:30px;background:#EEB422;margin:20px;position:relative;display: inline-block;top: 5px;} #email{width:50px;height:35px;background:#EEB422;margin:20px;position:relative;display: inline-block;top: 5px;} #email:before{border:25px solid transparent;border-top:20px solid #fff;content: "";position: absolute;left:0px;top: 2px;} #email:after{border:25px solid transparent;border-top:20px solid #EEB422;content: "";position: absolute;top:0px;} #file{width:30px;height:45px;border:4px solid #EEB422;margin:20px;position:relative;display: inline-block;top: 5px;} #file:before{border:10px solid #fff;border-right:10px solid #EEB422;border-bottom:10px solid #EEB422;content: "";position: absolute;left:-4px;top: -4px;} #file:after{width:20px;height:5px;border-top:3px solid #EEB422;border-bottom:3px solid #EEB422;content: "";position: absolute;left: 5px;top: 25px;} #history{width:35px;height:35px;border:4px solid #EEB422;border-radius: 50%;margin:20px;position:relative;display: inline-block;top: 5px;} #history:before{width:14px;height:14px;border-bottom:4px solid #EEB422;border-left:4px solid #EEB422;content: "";position: absolute;left:14px;top: 3px;} #video{width:50px;height:35px;background:#EEB422;border-radius: 20%;margin:20px;position:relative;display: inline-block;top: -5px;} #video:before{width:6px;height:6px;border:11px solid transparent;border-right:11px solid #EEB422;content: "";position: absolute;left:35px;top: 4px;} #video:after{width:10px;height:10px;border:6px solid transparent;border-top:6px solid #EEB422;border-left:6px solid #EEB422;transform:rotate(45deg);-webkit-transform:rotate(45deg);content: "";position: absolute;left:13px;top: 35px;} #tags{width:50px;height:25px;background:#EEB422;border-radius: 35% 0% 0% 35%;transform:rotate(45deg);-webkit-transform:rotate(45deg);margin:20px;margin-left:35px;position:relative;display: inline-block;top: -5px;} #tags:before{width:10px;height:10px;border-radius:50%;background:#fff;content: "";position: absolute;left:7px;top: 7px;} #phone{width:50px;height:50px;border-left:6px solid #EEB422;border-radius:20%;transform:rotate(-30deg);-webkit-transform:rotate(-30deg);margin:20px;margin-right:0px;position:relative;display: inline-block;top: -5px;} #phone:before{width:15px;height:15px;background:#EEB422;border-radius: 20%;content: "";position: absolute;left:-2px;top: 1px;} #phone:after{width:15px;height:15px;background:#EEB422;border-radius: 20%;content: "";position: absolute;left:-3px;top: 34px;} #profile{width: 40px;height:15px;background:#EEB422;border-radius: 45% 45% 0 0;margin:20px;position:relative;display: inline-block;top: 0px;} #profile:before{width: 20px;height:22px;background:#EEB422;border-radius:40%;content: "";position: absolute;left: 10px;top: -22px;} </style> <body> <div id="wraper"> <div id="power"></div> <div id="play"></div> <div id="pause"></div> <div id="stop"></div> <div id="comment"></div> <div id="like"></div> <div id="search"></div> <div id="home"></div> <div id="photo"></div> <div id="email"></div> <div id="file"></div> <div id="history"></div> <div id="video"></div> <div id="tags"></div> <div id="phone"></div> <div id="profile"></div> </div> </body>
|
如图:

总结
以上就是::after与::before的一些属性说明以及常见用法,我们只要知道伪元素并不是dom中的真实元素,而是一种CSS修饰,伪元素的display可以随意变换,因此可以做出很多好玩的样式,对于一些修饰类的元素,我们可以直接使用伪元素来实现,这样dom结构也会很紧凑和干净~