探索!单标签实现酷炫的css动画

背景

在上一篇文章一个炫酷的css动画里面,我们实现了一个酷炫的css动画。

那个最终实现上面,用了很多的标签在里面,有一些是效果需要,但是有一些是可以精简的。

于是想减少一下标签的使用来实现类似的效果,既然减少了,不如干脆一点,我们就用一个标签来尝试实现类似的效果。(不一完全一样的想效果,有些效果一个标签不好实现,下文会详细提到)

这是我们最终用单标签将要实现的效果。

老规矩,先分析一下效果,一共有六个部分,最外层圈,第二层圈,下面的一对圆环,上面的一对圆环,还有类流星雨动画的元素。

先把唯一的一个元素放好。

<div class="box"></div>

好,就这一个元素,html部分结束,下面全是css部分了!!!

最外层圈

这里第一反应应该是border,但是其实还有outline可以用,这里我们把border留给第二层用,我们第一层用outline来实现。

js 复制代码
.box {
        width: 300px;
        height: 300px;
        border-radius: 50%;
        outline: 2px solid rgb(42, 153, 255);
        outline-offset: 10px;
      }

得到外面的圆环

第二层圈

第二层我们用border, 然后把上下或者左右的边设为透明

box的样式上加上这些代码

js 复制代码
{
 border: 5px solid rgb(42, 153, 255);
        border-left-color: transparent;
        border-right-color: transparent;
}

下面的一堆圆环

上一篇文章里面,我们用了两种方式实现这个圆环

一种是conic-gradientmask,先利用角向渐变生成扇形,然后用mask遮住下面部分,得到圆环,然后重复多个,给每个不同的旋转角度。

第二种是repeating-conic-gradientmask,就是一次性生成带黑色间隔的扇形,然后mask遮住。

这里面我们还有第三种实现方式:

repeating-radial-gradientrepeating-conic-gradient

重复的径向渐变加重复的角向渐变来实现。

径向渐变可以得到一个完整的圆环,角向渐变可以得到黑色间隙的一堆小圆环。 这里面我们给box加上background

js 复制代码
 background: repeating-radial-gradient(
            #000,
            #000 50%,
            transparent 50%,
            transparent 60%,
            #000 60%,
            #000 100%
          ),
          repeating-conic-gradient(
            rgb(42, 153, 255) 0,
            rgb(42, 153, 255) 4%,
            transparent 4%,
            transparent 5%
          );

上面的一堆圆环

上面的一堆圆环实现起来其实和下面的一样,只是我们不能再用box的backgorund来实现了,因为有一个3d效果,需要沿着z轴做位移。

那我们其实还有两个工具没有用,那就是伪元素。这里我们先用一个::before

js 复制代码
.box::before {
        content: '';
        position: absolute;
        width: 300px;
        height: 300px;
        top: 0px;
        left: 0px;
        background: repeating-radial-gradient(
            #000,
            #000 50%,
            transparent 50%,
            transparent 60%,
            #000 60%,
            #000 100%
          ),
          repeating-conic-gradient(
            rgb(42, 153, 255) 0,
            rgb(42, 153, 255) 4%,
            transparent 4%,
            transparent 5%
          );
        transform: translateZ(200px);
      }

类流星雨元素

还剩下一个元素,我们就可以用另一个伪元素了,::after。 上一篇文章里面,我们用了一些元素来实现流星雨的动画,每一个元素代表其中一颗。这里我们只用一个伪元素实现的话,第一反应应该是用box-shadow来实现。

用box-shadow来实现对自身的多次复制,不过这里有一个缺陷,就是box-shadow默认是黑色,可以指定颜色但是不支持渐变。所以用box-shadow行不通,我们换一种方式来实现。

这里我们还是用repeating-linear-gradientmask来实现的。

重复的线性渐变实现几个自上而下的渐变色

然后我们再用mask,获得色条

js 复制代码
.box::after {
        content: '';
        position: absolute;
        width: 300px;
        height: 300px;
        top: 0px;
        left: 0px;
        background: #fff;
        background: repeating-linear-gradient(
          to bottom,
          transparent 0,
          transparent 80px,
          rgba(42, 153, 255, 0.1) 80px,
          rgb(42, 153, 255) 130px
        );
        -webkit-mask: repeating-linear-gradient(
          to right,
          transparent 0px,
          transparent 80px,
          #000 80px,
          #000 82px
        );
        transform: rotateX(90deg);
        animation: line 2s linear infinite;
      }

到这里,我们就完整的用单标签实现了这样的一个动画效果。

全部代码如下:

js 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        background: #000;
        display: flex;
        align-items: center;
        justify-content: center;
        padding-top: 300px;
        transform: translateZ(-150px);
        transform-style: preserve-3d;
      }
      .box {
        width: 300px;
        height: 300px;
        transform-style: preserve-3d;
        position: relative;
        border-radius: 50%;
        border: 5px solid rgb(42, 153, 255);
        border-left-color: transparent;
        border-right-color: transparent;
        outline: 2px solid rgb(42, 153, 255);
        outline-offset: 10px;
        background: repeating-radial-gradient(
            #000,
            #000 50%,
            transparent 50%,
            transparent 60%,
            #000 60%,
            #000 100%
          ),
          repeating-conic-gradient(
            rgb(42, 153, 255) 0,
            rgb(42, 153, 255) 4%,
            transparent 4%,
            transparent 5%
          );
        animation: rotate2 2s linear infinite;
      }

      .box::before {
        content: '';
        position: absolute;
        width: 300px;
        height: 300px;
        top: 0px;
        left: 0px;
        background: repeating-radial-gradient(
            #000,
            #000 50%,
            transparent 50%,
            transparent 60%,
            #000 60%,
            #000 100%
          ),
          repeating-conic-gradient(
            rgb(42, 153, 255) 0,
            rgb(42, 153, 255) 4%,
            transparent 4%,
            transparent 5%
          );
        transform: translateZ(200px);
        animation: rotate1 2s linear infinite;
      }
      .box::after {
        content: '';
        position: absolute;
        width: 300px;
        height: 300px;
        top: 0px;
        left: 0px;
        background: #fff;
        background: repeating-linear-gradient(
          to bottom,
          transparent 0,
          transparent 80px,
          rgba(42, 153, 255, 0.1) 80px,
          rgb(42, 153, 255) 130px
        );
        -webkit-mask: repeating-linear-gradient(
          to right,
          transparent 0px,
          transparent 80px,
          #000 80px,
          #000 82px
        );
        transform: rotateX(90deg);
        animation: line 2s linear infinite;
      }

      @keyframes line {
        0% {
          transform: translateZ(-50px) rotateX(90deg) rotateY(0deg);
        }
        100% {
          transform: translateZ(200px) rotateX(90deg) rotateY(-360deg);
        }
      }

      @keyframes rotate1 {
        0% {
          transform: translateZ(200px) rotateZ(0deg);
        }
        100% {
          transform: translateZ(200px) rotateZ(-720deg);
        }
      }
      @keyframes rotate2 {
        0% {
          transform: rotateZ(0deg);
        }
        100% {
          transform: rotateZ(360deg);
        }
      }
    </style>
  </head>
  <body>
    <div class="box"></div>
    <script>
      var elem = document.querySelector('body')
      var isDragging = false // 用于判断是否正在拖动
      var initialX = 0 // 初始鼠标X坐标
      var initialY = 0 // 初始鼠标Y坐标
      var currentX = 0 // 当前鼠标X坐标
      var currentY = 0 // 当前鼠标Y坐标
      var initialRotationY = 0 // 初始旋转角度(Y轴)
      var initialRotationX = 0 // 初始旋转角度(X轴)

      elem.addEventListener('mousedown', function (e) {
        // 当鼠标按下时
        initialY = e.clientY // 获取初始鼠标Y坐标
        initialRotationY = parseInt(
          getComputedStyle(elem)
            .getPropertyValue('transform')
            .replace(/[^0-9-.,]/g, '')
            .split(',')[4]
        ) // 获取初始旋转角度(Y轴)
        initialRotationX = parseInt(
          getComputedStyle(elem)
            .getPropertyValue('transform')
            .replace(/[^0-9-.,]/g, '')
            .split(',')[5]
        ) // 获取初始旋转角度(X轴)
        isDragging = true // 设置isDragging为true,表示正在拖动
      })

      document.addEventListener('mousemove', function (e) {
        // 当鼠标移动时
        if (isDragging) {
          // 如果正在拖动
          currentY = e.clientY // 获取当前鼠标Y坐标
          var dy = currentY - initialY // Y轴方向移动的距离
          var newRotationY = initialRotationY + dy * -1 // 根据移动方向计算新的旋转角度(Y轴)
          console.log(111, dy, newRotationY)

          elem.style.transform = 'rotateX(' + newRotationY + 'deg)' // 设置元素的旋转角度
        }
      })

      document.addEventListener('mouseup', function () {
        // 当鼠标松开时
        isDragging = false // 设置isDragging为false,表示已经停止拖动
      })
    </script>
  </body>
</html>
相关推荐
bysking21 分钟前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓37 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_41140 分钟前
无网络安装ionic和运行
前端·npm
理想不理想v41 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云1 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:137971205871 小时前
web端手机录音
前端
齐 飞1 小时前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
神仙别闹1 小时前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
GIS程序媛—椰子2 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_0012 小时前
前端八股文(一)HTML 持续更新中。。。
前端·html