CSS 怎样写一个动画(从基础动画到3d动画)

7,547 阅读7分钟

以前看过许多教学视频,大部分讲师都是讲个大概,然后就开始无厘头的灌输知识了。直到我后来看到一位优秀讲师的视频,他的讲课模式是第一堂课展示成果。这样下来,当我看到最终效果,我就有心思去不断学习这个东西了。

今天我就效仿这位讲师的模式,话不多说,上效果~~

1. 简单的渐变动画


2. 稍复杂的关键帧动画


3. 结合transform 实现3d动画效果


看起来还行,学起来也非常容易。

那咱们就一步一步来玩把~~

transition

transition css3 的一大亮点,他常用的大概有以下一些属性:

大致代码如下,省略部分代码:

button {
  ...
  background-color: red;
  transition-property: opacity, background-color, border-radius; /* 列表以逗号分隔 */
  transition-duration: 0.5s;
  transition-timing-function: ease; /* 默认速度效果 */
  transition-delay: 1s;
  ...
}
button:hover {
  ...
  opacity: 0.3;  background-color: #fff000;
  border-radius: 100px;
  ...
}
当然,这样写起来有些麻烦,当然你可以简化:

button { 
 background-color: red; 
 transition: opacity  0.5s 1s ease, background-color  0.5s 1s ease, border-radius  0.5s 1s ease; 
}

以上代码每个逗号隔开4个参数,分别为 CSS 属性、过渡时间、停顿开始时间、速度曲线。 看起来好像还有点麻烦诶:

button {
  ...  
  background-color: red;  
  transition: all 0.5s 1s ease;
  ...
}

这样看起来是不是简单多了呢?因为在大部分情况下,我们动画的多种效果一般是同时进行,同时消失的,如果时间不同会变成怎样的一个效果嘞?

transition: opacity  0.5s 1s ease, background-color  1.5s 2s linear, border-radius  0.5s cubic-bezier(0.215, 0.610, 0.355, 1);


所以因此我们可以用一个all便把所有相同效果的css属性代替啦~


嘻嘻,这样是不是又好看,代码还简洁呢?

对于 transition-timing-function 这里给大家推荐一个很好用的网站,可以随意调试你想要的贝塞尔速度曲线,点击GO!查看效果。复制最上面的代码,就可以使用到你的代码啦~

点击这里: 我也要去看看效果!


animation + @keyframes

animation 才是css3动画的一个进阶,他配合@keyframes,可以实现更加复杂的你想要的动画行为。
  • animation-name  --规定需要绑定到选择器的 keyframe 名称
  • animation-duration  --规定完成动画所花费的时间,以秒或毫秒计
  • animation-timing-function  --规定动画的速度曲线
  • animation-delay  --规定在动画开始之前的延迟
  • animation-iteration-count  --规定动画应该播放的次数
  • animation-direction  --规定是否应该轮流反向播放动画
  • animation-play-state  -- paused|running  属性规定动画正在运行还是暂停
一个一个写还是会略显复杂,这里就直接最终代码效果啦~

button{
  animation: ani 5s 2s infinite ease;
}

@keyframes ani {
  20%{    opacity: 0.3;  }
  40%{    border-radius: 100px;  }
  60%{    background-color: #fff000;  }
}

这里的keyframes就像是你声明了一个动画函数,ani就是你的函数名。animation就是去这个button中去执行函数。5个参数分别代表 动画函数名、过渡时间、停顿开始时间、动画的次数(infinite代表无限)、速度曲线。



animation+transform 3d动画

终于到达最激动人心的时刻了。前面的简单动画可能大部分人都会,不过3d动画可能还是有少数人使用的,它涉及一些3d思想,可能对一些童鞋们较为抽象。不过今天咱们就一点点的来学。其实也很简单~~

话不多说,咱们要实现一个正方体,当然是需要6个平面嘛?(emmmm 这不废话,幼儿园就会了);

老板,给我来六个花花绿绿的div!

<p>客观,您要的div:</p>
<div class="aniBox">  
  <div class="ani1"></div> 
  <div class="ani2"></div>
  <div class="ani3"></div>
  <div class="ani4"></div>
  <div class="ani5"></div>
  <div class="ani6"></div>
</div>

.aniBox {
  width: 220px;
  height: 220px;
}
.aniBox>div {
  width: 100%;
  height: 100%;
}
.ani1 {
  background: #4879dc;
}
.ani2 {
  background: #3bd168;
}
.ani3 {
  background: #e31653;
}
.ani4 {
  background: #1ed3eb;
}
.ani5 {
  background: #e9c80f;
}
.ani6 {
  background: #821fd3;
}

好嘞客官,这是您的div,我给您放到一个大div装好了~~

这里是效果图。。。。


???

emmmm 老板,都从袋子出来了,给我包好~~

.aniBox {
  position: relative;
  width: 220px;
  height: 220px;
}
.aniBox>div {
  position: absolute;
  width: 100%;
  height: 100%;
}


好了,6个div都放到一起啦,开始搞6个面喽;用transform来旋转位移它。


中间的红色,你可以想象成文档流的平面。现在想要将第一个面向前移动div一半的距离:

.ani1 {
  background: #4879dc;
  transform: translateZ(110px) /*前*/
}


咦 好像没什么变化哎,我明明把 #4879dc  颜色的移动到最前面的位置了呀?经过研究,最后我找到了一个属性transform-style: preserve-3d,这个属性规定如何在 3D 空间中呈现被嵌套的元素。必须设置在父元素身上,并且父元素有转换(就是有变形),并且子元素也得有转换(变形)才能看得到效果。

  • transform-style: flat  --子元素将不保留其 3D 位置 
  • transform-style: preserve-3d  --子元素将保留其 3D 位置

┗|`O′|┛ 嗷~~ 这样就懂啦:

.aniBox {
  position: relative;
  transform-style: preserve-3d;
  width: 220px;
  height: 220px;
}


哈哈哈,效果出来了。

好的! 开始其他的五个面~~~

.ani2 {
  background: #3bd168;
  transform: translateZ(-110px)  /*后*/
}
.ani3 {
  background: #e31653;
  transform: rotateY(90deg) translateZ(110px)  /*右*/
}
.ani4 {
  background: #1ed3eb;
  transform: rotateY(-90deg) translateZ(110px)  /*左*/
}
.ani5 {
  background: #e9c80f;
  transform: rotateX(90deg) translateZ(110px)  /*上*/
}
.ani6 {
  background: #821fd3;
  transform: rotateX(-90deg) translateZ(110px)  /*下*/
}

咦,好像被挡住了看不出什么效果诶~~~ 算了 咱们直接在控制台玩把:

哈哈,成功了,看起来有效果了,好了 咱们给他加上动画把~~

.aniBox {
  position: relative;
  margin: 30px auto;
  transform-style: preserve-3d;
  width: 220px;
  height: 220px;
  animation: box-3d 5s infinite;
}
@keyframes box-3d {
  100% {
    transform: rotateX(360deg) rotateZ(-720deg)
     /* 让他的结束角度 都为360的整数倍,这样他就可以看起来无缝衔接 */  
  }
}


咦,这个动画好像先快后慢诶?加个linear把 这样就看起来均匀了:

.aniBox {
  animation: box-3d 5s infinite linear;
}


本来以为已经完工了,可是总觉得有点不对劲。网上找了找,嗷~~还差一个近大远小的效果!

  • perspective  --属性定义 3D 元素距视图的距离,以像素计。该属性允许您改变 3D 元素查看 3D 元素的视图。当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本身。

emmmm 网上的说法好难理解。我自己用自己的想法给大家解释一下。

我把perspective看作一个房屋从中间到人面前的距离。(额~~还是不懂,算了,上图把!)


就是这个正方体,你可以当作你的房间大小,而 perspective 你可以当作这个 红面与面ABCD 的距离。

既然是房间,那就需要包装一下这个立方体咯~:

<div class="perBox">
      <div class="aniBox">
        <div class="ani1"></div>
        <div class="ani2"></div>
        <div class="ani3"></div>
        <div class="ani4"></div>
        <div class="ani5"></div>
        <div class="ani6"></div>
      </div>
</div>

.perBox {  perspective: 800px;}


是不是立体了好多呢????

什么 看起来没啥效果???

这好办,你想想,加入一个杯子放在一间屋子的最中间,而你站在房屋的窗玻璃处,是不是房屋越小,你看着越具体? 好的 咱们把房屋弄小一点把!

.perBox {  perspective: 400px;}


哦吼吼~~够立体了把! ?

什么你想看这个盒子内部? 这个div的宽为220px,一半也就是110px;

那么,只要咱们小于110px,就能看里面了把?  试试来~~

.perBox {  perspective: 100px;}


啊哈哈哈,有没有晕?有没有显卡燃烧的感觉!!!?

燃烧你的GPU!

咱们的动画也就讲到这啦,下来咱们看看perspective这玩意的兼容性:


哦no~  可怕 。

附加 几个好玩的 demo:

github.com/evelope/CSS…

github.com/evelope/My-…