纯CSS特效之-碎片旋转

2020-09-23  本文已影响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);
  }
}

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

上一篇下一篇

猜你喜欢

热点阅读