美文网首页
纯CSS特效之-碎片旋转

纯CSS特效之-碎片旋转

作者: 某时橙 | 来源:发表于2020-09-23 20:10 被阅读0次

    最近在codepen上看到一个特效名为polygon Sphere
    (PS:直接翻译多边形球体总感觉不能描述这个特效,这里特地形象的取了一个名字:碎片旋转)
    效果如下:

    效果.gif

    实现也非常简单,下面对其源代码进行一一解释:
    html部分

    .container
      - for (var i = 0; i < 30; i++)
        .circle
          - for (var j = 0; j < 25; j++)
            .content
    

    这里运用了Pug来直接生成大量的html标签,有编程经验的小伙伴可能可以直接猜到效果了,(如果对后面的文字感到困惑你可以直接看下面翻译后的代码)即在class为container的div下生成30个class为circle的div,其中每个circle包含25个class为content的div。
    翻译后的html

    <div class="container">
    <div class="circle">*25
     <div class="content"></div>*30
    </div>
    </div>
    

    下面我们看看css部分,因为这里用的是css的预编译器sass,所以我强烈建议您有不懂的地方可以查看sass的官方文档(不过我也会在下面尽可能的解释)
    这里没有什么好解释的,相信聪明的你完全可以自己看懂

    $BG: #262626; //背景色
    $CIRCLE_NUM: 30; //圈的个数
    
    html {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    
    body {
      position: relative;
      width: 100%;
      height: 100%;
      margin: 0;
      font-family: "Cute Font", Roboto, sans-serif;
      overflow: hidden;
      background-color: $BG;
    }
    
    * {
      &:before,
      &:after {
        position: absolute;
        content: "";
      }
    }
    
    .container {
      position: relative;
      width: 300px;
      height: 500px;
      margin: auto;
      transform: scale3d(1.0, 1.0, 1.0);
    }
    

    值得一提的是下面的

    * {
      &:before,
      &:after {
        position: absolute;
        content: "";
      }
    }
    

    为什么要给所有盒子添加before和after伪元素?实际上codepen作者在这里偷了个懒,马上我就会解释这里before和after的作用了!
    我打算对这个特效的解读采用自底向上的方法。我们先解释最小单元content元素。

      .content {
       position: absolute;
            width: random(150) + px;
            height: random(50) + px;
            top: 40%;//这里是为了使元素大致处于父元素中心
            left: 40%; //这里是为了使元素大致处于父元素中心
         @for $content from 1 through 25 {
              &:nth-child(#{$content}) {
                opacity: 0.5;
                clip-path: polygon(#{random(100)}% 0, #{random(100)}% 0, #{random(100)}% 48%); //画三角
              }
    }
    

    首先从定义三角形碎片开始,这里利用了clip-path 随机的画了3个点,刚好能形成一个三角形。
    $content是索引,索引1~25每个content(这里是三角形单元),每个三角形的形状都是随机的!

    然后给这个三角形上色(请先不要看下面的transfrom)

     @if $circle <= $CIRCLE_NUM / 2 {
                  background: hsl(245, random(100), 50);
                  //transform: rotate($content * 14.4deg) translate(0, #{($circle + 5 )* 10}px);
                }
                @else 
                  background: hsl(180, random(100), 50);
                  //transform: rotate($content * 14.4deg) translate(0, #{($CIRCLE_NUM - $circle + 5) * 10}px);
                }
    

    注意这里的if是为了给上下风暴区分主色调,你可以看看最顶上的gif,是不是上下的三角形颜色层次分明?


    基础三角形.png

    然后,如果一个三角形只有纯色调,就太单调了!
    所以这里要为内部的伪元素上色,并用clip-path完成挪动位置的效果

    &:before, &:after {
                  width: random(100) + px;
                  height: random(50) + px;
                  clip-path: polygon(#{random(100)}% 0, #{random(100)}% 0, #{random(100)}% 48%);
                } 
    
                &:before {
                  background: #fff;
                }
    
                &:after {
                  top: 10px;
                  left: 30px;
                  background: hsl(276, random(100), 50);
                  background: hsl(276, 100, 50);
                }
    
    上色后.png
    是不是有点不知所措看不懂?没关系,我去掉了content元素的clip-path,这下真相大白了!
    image.png
    定义好单独的三角形元素后,接下来就是要用三角形组成一个层,这个层的表现形式实际上就是一个个分层的圈,在html也是content的上级div:circle,PS:后面出现的$circle是层(圈)的索引 image.png
    如何完成这个圈的绘制?
    实际上就是让所有在中心的三角形转过一个角度,然后再向y轴移动一个位移
     @if $circle <= $CIRCLE_NUM / 2 {
                  background: hsl(245, random(100), 50);
                  transform: rotate($content * 14.4deg) translate(0, #{($circle + 5 )* 10}px);
                }
                @else {
                  background: hsl(180, random(100), 50);
                  transform: rotate($content * 14.4deg) translate(0, #{($CIRCLE_NUM - $circle + 5) * 10}px);
                }
              }
    

    transfrom的y轴中的算法,让015的圈越来越大,而1530的圈变的越来越小.这样便能形成一个螺旋的效果

    .circle {
      position: absolute;
      border-radius: 50%;
    
      @for $circle from 1 through $CIRCLE_NUM {
        &:nth-child(#{$circle}) {
          width: 200px;
          height: 200px;
          transform: skew(0, -10deg);
    
          top: #{$circle * 15}px; //让层之前有一定距离,这个距离是斜向的
          left: #{$circle * 3.22}px;//让层之前有一定距离 ,这个距离是斜向的
    
       //使层旋转,根据索引位置不同,产生不同的旋转方向
          @if $circle % 3 == 0 {
            animation: rotate-reverse #{$circle + random(10)}s linear infinite; 
          }
          @else {
            animation: rotate #{$circle + random(10) }s linear infinite;
          }
     .content {
            ...
         }
    

    使层转起来的动画

    @keyframes rotate {
      0% {
        transform: skew(0, -10deg) rotate(0);
      }
      100% {
        transform: skew(0, -10deg) rotate(360deg);
      }
    }
    
    @keyframes rotate-reverse {
      0% {
        transform: skew(0, -10deg) rotate(360deg);
      }
      100% {
        transform: skew(0, -10deg) rotate(0);
      }
    }
    

    scss最终源代码:

    $BG: #262626;
    $CIRCLE_NUM: 30;
    
    html {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    
    body {
      position: relative;
      width: 100%;
      height: 100%;
      margin: 0;
      font-family: "Cute Font", Roboto, sans-serif;
      overflow: hidden;
      background-color: $BG;
    }
    
    * {
      &:before,
      &:after {
        position: absolute;
        content: "";
      }
    }
    
    .container {
      position: relative;
      width: 300px;
      height: 500px;
      margin: auto;
      transform: scale3d(1.0, 1.0, 1.0);
    }
    
    .circle {
      position: absolute;
      border-radius: 50%;
    
      @for $circle from 1 through $CIRCLE_NUM {
        &:nth-child(#{$circle}) {
          width: 200px;
          height: 200px;
          transform: skew(0, -10deg);
    
          top: #{$circle * 15}px;
          left: #{$circle * 3.22}px;
    
          @if $circle % 3 == 0 {
            animation: rotate-reverse #{$circle + random(10)}s linear infinite;
          }
          @else {
            animation: rotate #{$circle + random(10) }s linear infinite;
          }
    
          .content {
            position: absolute;
            width: random(150) + px;
            height: random(50) + px;
            top: 40%;
            left: 40%;
    
            @for $content from 1 through 25 {
              &:nth-child(#{$content}) {
                opacity: 0.5;
                clip-path: polygon(#{random(100)}% 0, #{random(100)}% 0, #{random(100)}% 48%);
    
                &:before, &:after {
                  width: random(100) + px;
                  height: random(50) + px;
                  clip-path: polygon(#{random(100)}% 0, #{random(100)}% 0, #{random(100)}% 48%);
                } 
    
                &:before {
                  background: #fff;
                }
    
                &:after {
                  top: 10px;
                  left: 30px;
                  background: hsl(276, random(100), 50);
                  background: hsl(276, 100, 50);
                }
    
                @if $circle <= $CIRCLE_NUM / 2 {
                  background: hsl(245, random(100), 50);
                  transform: rotate($content * 14.4deg) translate(0, #{($circle + 5 )* 10}px);
                }
                @else {
                  background: hsl(180, random(100), 50);
                  transform: rotate($content * 14.4deg) translate(0, #{($CIRCLE_NUM - $circle + 5) * 10}px);
                }
              }
            }
          }
        }
      }  
    }
    
    @keyframes rotate {
      0% {
        transform: skew(0, -10deg) rotate(0);
      }
      100% {
        transform: skew(0, -10deg) rotate(360deg);
      }
    }
    
    @keyframes rotate-reverse {
      0% {
        transform: skew(0, -10deg) rotate(360deg);
      }
      100% {
        transform: skew(0, -10deg) rotate(0);
      }
    }
    

    是不是很简单?赶紧自己动手实现一个~

    相关文章

      网友评论

          本文标题:纯CSS特效之-碎片旋转

          本文链接:https://www.haomeiwen.com/subject/brioyktx.html