CSS系列,你了解伪元素吗

2,140 阅读4分钟

前言

说起伪元素,很容易和伪类混淆,他们的使用方法非常相似
标准写法伪类是用一个:,例如 :hover
而伪元素则是::,例如:::before,虽然一个 : 也会生效,但是不推荐


常用的伪元素

目前兼容性达到可用的伪元素有以下几种

  • ::first-line
  • ::first-letter
  • ::before
  • ::after

::first-line

跟字面意思一样,它表示元素的第一行,我们来看一个例子

p::first-line {
  text-transform: uppercase;
  color: cornflowerblue;
}
<p>
  This is a somewhat long HTML paragraph that will be broken into several
  lines. The first line will be identified by a fictional tag sequence. The
  other lines will be treated as ordinary lines in the paragraph.
</p>

这一段代码把段落的第一行字母变为大写,需要注意的是第一行指的是排版后显示的第一行,跟 HTML 代码中的换行无关


CSS 标准规定了 first-line 必须出现在最内层的块级元素之内

div > p#a {
  color: green;
}
div > span#a {
  color: green;
}
div::first-line {
  color: blue;
}
<div>
  <p id="a">First paragraph</p>
  <p>Second paragraph</p>
</div>
<div>
  <span id="a">First paragraph</span><br />
  <span>Second paragraph</span>
</div>

以上效果可以看出
p 标签为块级元素,伪元素出现在块元素内,并且蓝色覆盖了绿色属性
再来看 span 标签,还是绿色,显然伪元素没有在行内标签中生效


::first-letter

表示文本首字母,常见的一种文字排版方式是首字母大写并且浮动在最左边

p::first-letter {
  text-transform: uppercase;
  font-size: 2em;
  padding-right: 0.3em;
  float: left;
}
<p>
  This is a somewhat long HTML paragraph that will be broken into several
  lines. The first line will be identified by a fictional tag sequence. The
  other lines will be treated as ordinary lines in the paragraph.
</p>

它与 ::first-line 的区别在于,可作用于任何标签

div > span#a {
  color:green;
}
div::first-letter { 
  color:blue; 
}
<div>
  <span id="a">First paragraph</span><br />
  <span>Second paragraph</span>
</div>


::first-line 和 ::first-letter 支持的属性


::before 和 ::after

这两个伪元素跟前面两个不同的是,它不是把已有的内容套上一个元素,而是真正的无中生有,造出一个元素

  • ::before 表示在元素内容之前插入一个虚拟的元素
  • ::after 则表示在元素内容之后插入
    这两个伪元素所在的 CSS 规则必须指定 content 属性才会生效,看下例子:
p.special::before {
  display: block;
  content: 'pseudo! ';
}
p.special::after {
  display: block;
  content: counter(chapno, upper-roman) '. ';
}
<p class="special">I'm real element</p>

::before 和 ::after 中支持所有的 CSS 属性。实际开发中,这两个伪元素非常有用,有了这两个伪元素,一些修饰性元素,可以使用纯粹的 CSS 代码添加进去,这能够很好地保持 HTML 代码中的语义,既完成了显示效果,又不会让 DOM 中出现很多无语义的空元素


一个div实现太极图

今天遇到到一个好玩的例子:
结合伪元素,使用一个div实现旋转的太极图,那么让我们看看实现思路吧

太极图背景

使用 border-left border-right border-radius 来画一个太极图背景

.tj {
   position: relative;
   width: 0;
   height: 200px;
   border-left: 100px solid #ffffff;
   border-right: 100px solid #000000;
   border-radius: 100%;
   box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
 }

太极图内部结构

利用伪元素 ::before ::after 及边框圆角特性,在内部画两个边框颜色与背景色相同的粗边框空心圆,哈哈哈真绕嘴,看下效果:

为方便理解内部结构,换个直观的颜色:

.tj::before {
  content: '';
  position: absolute;
  box-sizing: border-box;
  width: 100px;
  height: 100px;
  border: 35px solid #ffffff;
  background-color: #000000;
  border-radius: 100%;
  left: -50px;
  top: 100px;
}
.tj::after {
  content: '';
  position: absolute;
  box-sizing: border-box;
  width: 100px;
  height: 100px;
  border: 35px solid #000000;
  background-color: #ffffff;
  border-radius: 100%;
  left: -50px;
  top: 0;
}

动画

最后让太极图转起来

@keyframes rotation {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}
.tj{
 /*...*/
 animation: rotation 3.33s linear infinite;
}

最终效果

完整代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    @keyframes rotation {
      0% {
        transform: rotate(0);
      }
      100% {
        transform: rotate(360deg);
      }
    }
    .tj {
      position: relative;
      width: 0;
      height: 200px;
      border-left: 100px solid #ffffff;
      border-right: 100px solid #000000;
      border-radius: 100%;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
      animation: rotation 3.33s linear infinite;
    }
    .tj::before {
      content: '';
      position: absolute;
      box-sizing: border-box;
      width: 100px;
      height: 100px;
      border: 35px solid #ffffff;
      background-color: #000000;
      border-radius: 100%;
      left: -50px;
      top: 100px;
    }
    .tj::after {
      content: '';
      position: absolute;
      box-sizing: border-box;
      width: 100px;
      height: 100px;
      border: 35px solid #000000;
      background-color: #ffffff;
      border-radius: 100%;
      left: -50px;
      top: 0;
    }
  </style>
  <body>
    <div class="tj"></div>
  </body>
</html>

总结

  • 加深对伪元素特性及使用方式的了解
  • 对例子中用到的常用且实用的属性做了以下整理
    • border
      • border-left
      • border-right
      • border-radius
    • 伪元素
      • ::before
      • ::after
    • box-sizing 盒模型相关
      • border-box
    • position
      • relative
      • absolute
    • animation
      • animation-name
      • animation-duration
      • animation-timing-function
      • animation-iteration-count

巩固基础,发掘更多冷门小技巧 (!--)
如果你有更好玩的实现方式欢迎一起分享~~