CSS 实现一个太极图,循序渐进带你了解伪元素

1,729 阅读5分钟

本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力

前言

本文将从使用 CSS 实现一个太极图,作为出发点,循序渐进,让大家了解到伪元素能解决什么问题?和为什么会有伪元素,那现在就可以动手,写代码,实现一个太极吧。

实现太极图

html 代码

<div class="yinyang">
  <div class="one"></div>
  <div class="two"></div>
</div>

css 代码

* {
  padding: 0;
  margin: 0;
}

body {
  background: rgb(152, 152, 152);
}

.yinyang {
  position: relative;
  width: 200px;
  height: 200px;
  margin: 100px auto;
  border-radius: 50%;
  background: linear-gradient(to bottom, #fff 0%, #fff 50%, #000 50%, #000 100%);
}

.yinyang > .one {
  box-sizing: border-box;
  position: absolute;
  left: 0;
  top: 50px;
  width: 100px;
  height: 100px;
  border: 40px solid #000;
  border-radius: 50%;
  background: #fff;
}

.yinyang > .two {
  box-sizing: border-box;
  position: absolute;
  right: 0;
  top: 50px;
  width: 100px;
  height: 100px;
  border: 40px solid #fff;
  border-radius: 50%;
  background: #000;
}

上面的代码可以优化吗?可以优化的,我们看看上面的 CSS 代码,是不是重复相同的代码,这就可以优化。

可以改成这样。

* {
  padding: 0;
  margin: 0;
}

body {
  background: rgb(152, 152, 152);
}

.yinyang {
  position: relative;
  width: 200px;
  height: 200px;
  margin: 100px auto;
  border-radius: 50%;
  background: linear-gradient(to bottom, #fff 0%, #fff 50%, #000 50%, #000 100%);
}

.yinyang > .one,
.yinyang > .two {
  box-sizing: border-box;
  position: absolute;
  top: 50px;
  width: 100px;
  height: 100px;
  border-radius: 50%;
}

.yinyang > .one {
  left: 0;
  border: 40px solid #000;
  background: #fff;
}

.yinyang > .two {
  right: 0;
  border: 40px solid #fff;
  background: #000;
}

可以让太极动起来吗?可以,需要使用到 CSS3 动画:animation。

完整的代码:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手把手教你用 css 画太极</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    body {
      background: rgb(152, 152, 152);
    }

    .yinyang {
      position: relative;
      width: 200px;
      height: 200px;
      margin: 100px auto;
      border-radius: 50%;
      background: linear-gradient(to bottom, #fff 0%, #fff 50%, #000 50%, #000 100%);
      animation: spin 3s linear infinite;
    }

    .yinyang > .one,
    .yinyang > .two {
      box-sizing: border-box;
      position: absolute;
      top: 50px;
      width: 100px;
      height: 100px;
      border-radius: 50%;
    }

    .yinyang > .one {
      left: 0;
      border: 40px solid #000;
      background: #fff;
    }

    .yinyang > .two {
      right: 0;
      border: 40px solid #fff;
      background: #000;
    }
    /* css3 动画 */
    @keyframes spin {
      0% {
          transform: rotate(0deg);
      }
      100% {
          transform: rotate(360deg);
      }
    }
  </style>
</head>

<body>
  <div class="yinyang">
    <div class="one"></div>
    <div class="two"></div>
  </div>
</body>

</html>

上面的代码还可以继续优化吗?可以,不知道大家有没有留意到两个 div 的作用,仅仅是用来布局显示,没有其他作用,那我们可以不使用 div 吗?这就要使用到我们的伪元素啦。

优化

我们在上一版的代码,不使用那两个 div 元素,改用伪元素来实现。我们来看看,怎么改造吧。

其实就是删掉那两个 div,将 .yinyang > .one 改成 .yinyang::before,还有将 .yinyang > .two 改成 .yinyang::after

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手把手教你用 css 画太极</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    body {
      background: rgb(152, 152, 152);
    }

    .yinyang {
      position: relative;
      width: 200px;
      height: 200px;
      margin: 100px auto;
      border-radius: 50%;
      background: linear-gradient(to bottom, #fff 0%, #fff 50%, #000 50%, #000 100%);
      animation: spin 3s linear infinite;
    }

    .yinyang::before,
    .yinyang::after {
      box-sizing: border-box;
      position: absolute;
      top: 50px;
      width: 100px;
      height: 100px;
      border-radius: 50%;
      content: '';
    }

    .yinyang::before {
      left: 0;
      border: 40px solid #000;
      background: #fff;
    }

    .yinyang::after {
      right: 0;
      border: 40px solid #fff;
      background: #000;
    }
    /* css3 动画 */
    @keyframes spin {
      0% {
          transform: rotate(0deg);
      }
      100% {
          transform: rotate(360deg);
      }
    }
  </style>
</head>

<body>
  <div class="yinyang"></div>
</body>

</html>

效果图

阴阳.gif

我们来审查下元素,看下是否有什么不一样的地方。

你会发现了 div 元素里面多了::before 和 ::after,而且有对应的样式。

image.png

回到正题

什么是伪元素?

伪元素的语法跟伪类相似,不过表现得是像你往标记文本中加入全新的HTML元素一样,产生的效果是把不存在的元素硬选出来。

简单来说,伪元素,就不是真正的元素,真正的元素,就比如是上面例子用到的 div 元素。

伪元素有哪些?

  • ::before:表示在元素内容之前插入一个虚拟的元素「常用」
  • ::after:表示在元素内容之后插入一个虚拟的元素「常用」
  • ::first-letter:选中某块级元素第一行的第一个字母,并且文字所处的行之前没有其他内容(如图片和内联的表格)
  • ::first-line:在某块级元素的第一行应用样式
  • ``::cue`:匹配所选元素中的WebVTT提示
  • ::selection:应用于文档中被用户高亮的部分(比如使用鼠标或其他选择设备选中的部分)
  • ::slotted:用于选定那些被放在 HTML 模板中的元素

除了 ::after::before,其他的,我平时都用不到。对其他伪元素感兴趣的话,可以查下 mdn,实现 demo,看看。

一张图片,知道伪元素有那些。

image.png

::before 与 ::after

::before 和 ::after 伪元素是最常用、最经典的。 ::before 表示在元素内容之前插入一个虚拟的元素, ::after 则表示在元素内容之后插入,并且 ::before 和 ::after 中支持所有的 CSS 属性。

但需要注意的是这两个伪元素所在的 CSS 规则必须指定 content 属性才会生效,也就是你没有设置 content 的话,就没有效果。

content 属性取值

  • string
  • attr()
  • url()/uri()
  • 计数器

string

<p>追梦玩家</p>
<style>
  p::before {
    content: '「';
    color: blueviolet;
  }
  p::after {
    content: '」';
    color: blueviolet;
  }
</style>

效果图

image.png

attr()

<a href="https://juejin.cn/user/2911162520331037">「追梦玩家」</a>
<style>
  a::after {
    content: ' → ' attr(href); /* 在 href 前显示一个箭头 */
  }
</style>

效果图 image.png

url()/uri()

<p>「追梦玩家」</p>
<style>
  p::after {
    content: url("https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/0f4dc5bd1dce1965c8c9cb947b4f5018~300x300.image");
  }
</style>

效果图 image.png

计数器

<style>
  body {
    counter-reset: id;
  }

  .items {
    width: 300px;
    margin: 60px 0;
  }

  .items > li {
    margin: 10px;
    padding: 5px 10px;
    background-color: yellowgreen;
  }

  .items > li::before {
    counter-increment: id;
    content: '第'counter(id) '条:';
  } 
</style>
<ul class="items">
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
  <li>item4</li>
</ul>

效果图

image.png

伪元素的常见使用场景有?

清除浮动

相信大家,都用过吧,看看这个代码,熟悉不,这里就不多说了。

.clearfix::after {
  content: '';
  display: block;
  clear: both;
}

使用伪元素扩大点击区域/给你的点击区域加个触控热区

背景: 给图标(按钮、标签)做事件点击时,常常会因为元素面积太小导致用户很难点中,影响用户体验,产品大佬就会让我们做大点击区域,一般给元素加个 padding 就可以了,但这时 UI 就会偏差。

要实现产品大佬的想要的效果,我们可以怎么做呢?

给需要增加热区的元素加上add_touch类,即可在原来的基础上,增加1.5倍触控热区。就可以解决那个问题了。

.add_touch {
  position: relative;
}


.add_touch::after {
  content'';
  width100%;
  height100%;
  position: absolute;
  left0;
  top0;
  transformscale(1.5);
}

做个气泡

<span class="welcome">Hello</span>
<style>
  .welcome {
    position: relative;
    display: inline-block;
    margin-bottom: 26px;
    padding: 4px 16px;
    color: #fff;
    background-color: #E6686A;
    line-height: 22px;
  }
  .welcome::after{
    position: absolute;
    top: 100%;
    left: 4px;
    width: 0;
    height: 0;
    border: 10px solid transparent;
    border-top-width: 0;
    border-left-color: #E6686A;
    content: '';
  }
</style>

效果图

image.png

参考

写到最后

伪元素的语法跟伪类相似,不过表现得是像你往标记文本中加入全新的HTML元素一样,产生的效果是把不存在的元素硬选出来。

文中如有错误,欢迎在评论区指正,如果这篇文章帮助到了你或者喜欢,欢迎点赞和关注。