关于元素的 ::before 和 ::after 伪元素,我们接触过不少,但基本都是零零星星的,这里有必要梳理一下。
我们先做个简单一点的元素,然后再依次给它加上两个伪元素:
<style>
.mnBox {
width: 400px;
height: 200px;
border: 1px solid gray;
position: relative;
}
/* 这里添加伪元素代码 */
</style>
<div class="mnBox"></div>
效果:
这个真的简简单单,没什么要解释的,唯独要强调的是 mnBox 盒子的 position 属性,要定位,一般建议相对定位,即,position: relative;,特殊需要时也可以采用其他定位,如绝对定位(absolute)。因为只有父元素定位了,将来子元素所做的定位才会以父元素做参照,而前述两个伪元素,我们以前反复提及,它们是特殊的子元素。
下面我们先加入 ::before 伪元素,CSS代码放在 .mnBox {} 之后:
.mnBox::before {
position: absolute;
content: '伪元素 ::before';
width: 150px;
height: 50px;
left: 10px;
top: 10px;
background: olive;
color: orange;
padding: 10px;
}
绝对定位(position: absolute;)是强烈建议的,这么做,配合父元素的 relative 定位,伪元素就会以父元素为自己的定位参照,不至于找不着北;content 属性是必须的,否则伪元素渲染不出来,其值可以为空字串、实字串,也可以是相关变量(我们后面会简单谈到 attr 变量)。其他方面,从代码中可以看到,和元素的属性设置没有区别,拥有常规元素的一切属性,可以设置尺寸、物理位置、内边距、前景色和背景色等等。
html代码无需改变,效果就出来了:
加 ::after 伪元素道理同 ::before,下面的代码加在 CSS 里面,习惯上放在 *::before {} 之后:
.mnBox::after {
position: absolute;
content: '伪元素 ::after';
width: 150px;
height: 150px;
left: 100px;
top: 50px;
background: teal;
color: orange;
padding: 10px;
}
效果:
上面效果,我们看到,伪元素 ::after 的盒子溢出了父盒子。这是正常现象:伪元素隶属于父元素,但它可以拥有自己的尺寸和位置,其物理位置和尺寸最终导致它身居何处,但这一切,由于有了父子关系的 position 配套定位的约束,我们在设计的时候就都可以预见得到,因为,在我们营造的环境里,伪元素的定位总是以父元素为参照,参照点是父元素的左上角的 xy坐标 {0,0}。同时,请观察一下 ::before 和 ::after 的层级关系:后者总是后来者居上(不论CSS代码中两个伪元素谁先谁后)。
请特别注意:伪元素必须使用 content 属性,单词是“内容”之意,它用来表明伪元素的内容,如我们前例伪元素显示的文本(不需要伪元素文本的,请用空字串表示,即 '')。伪元素要显示的文本,可以在 CSS 里设定,也可以在 HTML 代码中指定,这时,CSS伪元素代码中,需要使用 attr 变量:
content: attr(data-mytext);
data- 是规定好的标准前缀,使用其他的字串替代 data 在一些编辑器中会被警告,但浏览器会支持。data- 之后紧跟着自定义的字串,可以是语义化的。然后,在HTML主元素代码中设定待输出内容:
<div class="mnBox" data-mytext="我是伪元素"></div>
还可以通过JS读取和写入 attr 数据:
<script>
let ele = document.querySelector('.mnBox'); //获得 mnBox 操作句柄
let dataStr = ele.dataset.mytext; //读取伪元素内的文本
console.log(dataStr); //控制台显示读取内容
ele.dataset.mytext = '我的文本修改了'; //修改伪元素文本内容
dataStr = ele.dataset.mytext; //再次读取伪元素内的文本
console.log(dataStr); //控制台显示新读取内容
</script>
dataset方法正是我们做模拟逐字同步歌词显示模块所用到的,虽然大家可能不怎么留意到该模块中JS的实现细节。
关于伪元素的一些扩展知识:
① 不是所有的HTML容器(元素)都拥有伪元素,一般说来,绝大多数双标签的容器都有伪元素,但也有例外,如 iframe 就没有伪元素;绝大多数的单标签容器没有伪元素,img 是个例外。
② 伪元素首先是假的,假在,常规方法在 DOM 树里面遍历不到它;同时它又是真真切切的元素,我们从上面的演示中可以感知到他的真实存在。总而言之,伪元素是一个伪造的元素,它真实存在但在 DOM 树种遍历不到它。
③ 伪元素和伪类的主要区别:概念和功能上,伪元素是对其所寄生的主元素的伪造,而伪类不伪造元素,而是用于制定主元素的特殊效果,亦即赋予元素一个自身不能制定的样式(如鼠标悬停在元素上面是改变文本颜色);写法上,CSS3规定,伪类有一个小角冒号引导(:hover),伪元素用的引导符号是一对小角冒号(::first-letter)。
④ 其他伪元素:CSS中常用到的共有四个伪元素,除了业已介绍的 ::before 和 ::after,还有:
::first-letter - 首字母相关
::first-line - 首行相关