Transition and Animation

24 篇文章 0 订阅

Transition

语法

1
2
3
4
5
6
7
.example {
  transition-property: all | none | <custom-ident>;
  transition-duration: 0s;
  transition-timing-function: ease | ease-in | ease-out | ease-in-out |
    cubic-bezier(<number>, <number>, <number>, <number>);
  transition-delay: 0s;
}

简写:

1
2
3
4
.example {
  transition: [transition-property] [transition-duration]
    [transition-timing-function] [transition-delay];
}

多个过渡效果:

1
2
3
.example {
  transition: width 2s linear, opacity 2s linear, color 2s linear;
}

 

触发过渡效果

仅定义过渡的规则,但是没有明确什么时候、如何触发过渡,将不会产生任何效果。

:hover :active :focus :checked这四个伪类元素都可以触发:

1
2
3
4
5
6
7
.example {
  background-color: green;
  transition: background-color 2s ease-in 1s;
}
.example:hover {
  background-color: blue;
}

媒体查询media

1
2
3
4
5
6
7
8
9
10
11
.example {
  width: 200px;
  height: 200px;
  transition: width 2s ease, height 2s ease;
}
@media only screen and (max-width: 960px) {
  .example {
    width: 100px;
    height: 100px;
  }
}

Javascript:

1
2
3
4
5
$(function() {
  $('#button').click(function() {
    $('.box').toggleClass('style-change')
  })
})
1
2
3
4
5
6
7
8
9
.box {
  width: 200px;
  height: 200px;
  transition: width 2s ease, height 2s ease-in;
}
.style-change {
  width: 300px;
  height: 300px;
}

Hover on 和 Hover off 的 Transition

1
2
3
4
5
6
7
8
9
.example {
  background-color: #ff9ebb;
  transform: rotate(720deg);
  transition: all 2s ease-out;
}
.example:hover {
  background-color: #ed2d50;
  transform: rotate(0deg);
}

一般我们不会在:hover时设置transition,这时,鼠标移动进入元素,元素按照:hover里定义的样式发生形变,鼠标移出移出元素时,元素的样式会过渡变回初始状态,如图:

让我们在:hover里也设置transition试一试:

1
2
3
4
5
6
7
8
9
10
.example {
  background-color: #ff9ebb;
  transform: rotate(720deg);
  transition: all 2s ease-out;
}
.example:hover {
  background-color: #ed2d50;
  transform: rotate(0deg);
  transition: background-color 2s linear 0.5s;
}

:hover时,后定义的transition会覆盖先定义的值,所以,鼠标移入元素时,只有background-color会发生变化,当鼠标移出元素时,先定义的transition: all 2s ease-out生效,backgound-colortransform都发生的变化。

综上所述,在:hover处定义的transition影响鼠标移入时的过渡效果,在元素内定义的transition起到的作用就如开始时提到,使元素的样式从:hover时的状态恢复的初始状态,表现为影响鼠标移出时的过滤效果:

点击看效果

cubic-bezier 函数实现弹跳效果

我们将实现一个小风扇弹跳展开的效果:

点击看效果

HTML 结构:

1
2
3
4
5
6
7
8
9
<div class="fan">
  <input type="checkbox" id="checkbox">
  <div class="leaf"></div>
  <div class="leaf"></div>
  <div class="leaf"></div>
  <div class="leaf"></div>
  <div class="leaf"></div>
  <div class="center"></div>
</div>

小风扇有 5 个扇叶,一个中心花蕊开关,一个checkbox,我们将checkbox定位在中心花蕊后面,通过checkbox勾选与取消勾选操作控制小风扇的打开与收起:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.fan {
  width: 60px;
  height: 120px;
  position: relative;
}
#checkbox {
  position: absolute;
  width: 40px;
  height: 50px;
  cursor: pointer;
}
.center {
  position: absolute;
  width: 45px;
  height: 50px;
  background-color: #fff;
  border-radius: 50%;
  pointer-events: none;
}

扇叶的形状可以通过border-radius绘制出来。可以看出扇叶是左右对称的,说明border-radius的水平半径是50%,其次扇叶上短下长,说明垂直半径上方少,下方长,即可设border-radius: 50% / 30% 30% 70% 70%:

1
border-radius: htl htr hbr hbl / vtl vtr vbr vbl;

从效果图中可以看出,扇叶的旋转中心并不是center center,而是扇叶上方的中心,已知扇叶宽60px,可得旋转中心坐标应为tranform-origin: 30px 30px:

1
2
3
4
5
6
7
8
9
.leaf {
  width: 60px;
  height: 120px;
  position: absolute;
  border-radius: 50% / 30% 30% 70% 70%;
  pointer-events: none;
  transform-origin: 30px 30px;
  transition: transform 1s;
}

下面设置扇叶旋转的位置,假设第三片扇叶旋转 180° 垂直向上,剩下四片扇叶依次间隔(360-60)/4=75px,别忘了这个例子触发过渡效果的方法是:checked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#checkbox:checked ~ .leaf:nth-of-type(5) {
  transform: rotate(35deg);
}

#checkbox:checked ~ .leaf:nth-of-type(4) {
  transform: rotate(105deg);
}

#checkbox:checked ~ .leaf:nth-of-type(3) {
  transform: rotate(180deg);
}

#checkbox:checked ~ .leaf:nth-of-type(2) {
  transform: rotate(255deg);
}

#checkbox:checked ~ .leaf:nth-of-type(1) {
  transform: rotate(325deg);
}

到这里,小风扇已经可以旋转了:

现在,只要改变transitiontransition-timing-function就是可以实现弹跳的效果了,在这之前,先了解一下cubic-bezier函数:

1
cubic-bezier(t1, d1, t2, d2)

t代表时间timed代表距离distance

假设由一个盒子要用 6s 的时间,从 A 点移动到 B 点,设t1=0, d1=1

1
cubic-bezier(0, 1, 0, 0)

从图中可以看出,盒子几乎没有花费任何时间从 A 点到达中点,然后匀速从中点向 B 点移动。

再设t1=1, d1=0

1
cubic-bezier(1, 0, 0, 0)

从图中可以看出,前 3s 盒子保持不动,然后几乎没有花费任何时间从 A 点到达中点,然后匀速从中点向 B 点移动。

再设t1=1, d1=1, t2=0, d1=1

1
cubic-bezier(1,1,0,1)

从图中可以看出,盒子用了 3s 的时间从 A 点移动到中点,然后几乎没用任何时间从中点移动到了 B 点。

从上面的例子中可以看出,t1 d1控制 A 点到中点的时间和距离,t2 d2控制中点到 B 点的时间和距离。

弹跳函数cubic-bezier的实现:

1
cubic-bezier(.8,-.5,.2,1.4)

细心的观察,小风扇打开和收起时的弹跳效果并不完全一样,这里需要用到上一节说到的hover on and off transition

1
2
3
4
5
6
.leaf {
  transition: transform 1s cubic-bezier(0.8, 0.5, 0.2, 1.4);
}
#checkbox:checked ~ .leaf {
  transition: transform 1s cubic-bezier(0.8, -0.5, 0.2, 1.4);
}

为小风扇设置两个transition,打开的时候先收缩一下。

5 种 hover 效果

 https://codepen.io/pennySU/pen/NMoBZe

picture wall

https://codepen.io/pennySU/pen/QrYrEX

扭曲拉直效果

https://codepen.io/pennySU/pen/qYgxJG

弹钢琴效果

https://codepen.io/pennySU/pen/KRJZKj

翻日历效果

https://codepen.io/pennySU/pen/JvxONd

Animation

定义一个动画需要设置animation子属性来配置动画的时间、时长等其他细节,动画的实际表现,是由@keyframes规则实现的。

语法

1
2
3
4
5
6
7
8
9
10
11
@keyframes Animation-name {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
#box {
  animation: Animation-name 5s infinite; /*多个动画可用逗号分隔*/
}

简写:

1
2
animation: duration | timing-function | delay | iteration-count | direction |
  fill-mode | play-state | name;

 

微博点赞效果

HTML 结构:

1
<div class="like"></div>

下图是用来实现动效的图片steps_praised.png

我们的思路是,点赞时,让图片从左到右按一定的速度动起来,实现动画效果,首先定义动画帧:

1
2
3
4
5
6
7
8
@keyframes steps {
  0% {
    background-position: left;
  }
  100% {
    background-position: right;
  }
}

动画帧很简单,从左到右移动即可。设置动画执行的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.like {
  position: relative;
  &:before {
    content: '';
    position: absolute;
    width: 23px;
    height: 28px;
    background-image: url(/steps_praised.png);
    background-repeat: no-repeat;
    background-size: 483px 28px;
  }
  &.active {
    background-position: right;
    &:before {
      animation: 0.65s steps(20) 1 forwards steps;
    }
  }
}

首先,给.like元素的伪元素:before通过background-image的方式设置点赞按钮的初始状态,当点击元素时,为元素添加.active类,执行动画。动画共进行0.65s,分20步,执行1次,执行完保持最后一帧的状态。steps(20)等同于steps(20,end)

背景图片steps_praised.png966px,共有 21 帧,设置background-size: 483px 28px;后,每帧动画的宽为483 / 21 = 23px,即:before的宽为23px。初始状态已经展示一帧了,所以只需展示剩下的 20 帧即可,故设置step(20),动画结束时保存最后一帧的状态。点击看效果

使用雪碧图制作动画,可减少 gif 的使用,一般 gif 文件的大小要大于雪碧图。雪碧图动画

Loading

JSFiddle 的 loading 效果。

HTML 结构:

1
2
3
4
<div class="jump">
  <svg class="loader"></svg>
  <span class="shadow"></span>
</div>

一个蓝胖子,一个阴影元素。蓝胖子上下有移动,也有缩小和放大,阴影有明暗和大小的变化。所以分别为它两定义动画的表现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@keyframes jump {
  from {
    transform: translateY(0) scale(1.15, 0.8);
  }
  20% {
    transform: translateY(-35px) scaleY(1.1);
  }
  50% {
    transform: translateY(-50px) scale(1);
  }
  80% {
    transform: translateY(-35px) scale(1);
  }
  to {
    transform: translateY(0) scale(1.15, 0.8);
  }
}

动画jump从下到上,再从上到下移动,同时由“矮”“胖”到“高”再到“正常”最后又变为“矮”“胖”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@keyframes scale-shadow {
  from {
    opacity: 0.3;
    transform: scale(1);
  }
  50% {
    opacity: 0.2;
    transform: scale(0.5);
  }
  to {
    opacity: 0.3;
    transform: scale(1);
  }
}

动画scale-shadow先变小然后恢复,透明度先变淡再变深。

1
2
3
4
5
6
.loader {
  animation: jump 0.8s ease-in infinite;
}
.shadow {
  animation: scale-shadow 0.8s ease-in infinite;
}

设置animation属性使动画动起来。点击看效果

再介绍一个利用负动画延迟animation-delay实现的 loading 效果。

HTML 结构:

1
2
3
4
5
6
7
8
9
10
<div class="roller" title="roller">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

一个roller容器,八个点点。

动画效果其实很简单,八个点点旋转完整的一圈:

1
2
3
4
5
6
7
8
@keyframes roller {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

定义动画roller旋转 360°。

为容器和点点设置一些样式:

1
2
3
4
5
6
7
8
.roller {
  width: 64px;
  height: 64px;
}
.roller div {
  margin: -3px 0 0 -3px;
  transform-origin: 32px 32px;
}

从效果图中,可以看出,八个点点的旋转中心是容器的中点,transform-origin是根据元素的左上角定位的,即八个div元素的位置必须是在同一个位置,这样它们才能有相同的旋转中心。所以我们用:before伪元素实现圆点的效果并且绝对定位形成一个半圆弧形状,保证八个div元素没有宽高使得它们都在同一个位置拥有相同的旋转中心。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
div {
  margin: -3px 0 0 -3px;
  transform-origin: 32px 32px;
  &:before {
    content: '';
    position: absolute;
    width: 6px;
    height: 6px;
    border-radius: 50%;
  }
  &:nth-child(1) {
    &:before {
      background-color: #ff2121;
      left: 50px;
      top: 50px;
    }
  }
  &:nth-child(2) {
    &:before {
      background-color: #ff7200;
      top: 54px;
      left: 45px;
    }
  }
  &:nth-child(3) {
    &:before {
      background-color: #ffdc59;
      top: 57px;
      left: 39px;
    }
  }
  &:nth-child(4) {
    &:before {
      background-color: #84d458;
      top: 58px;
      left: 32px;
    }
  }
  &:nth-child(5) {
    &:before {
      background-color: #7bc576;
      top: 57px;
      left: 25px;
    }
  }
  &:nth-child(6) {
    &:before {
      background-color: #2e89c1;
      top: 54px;
      left: 19px;
    }
  }
  &:nth-child(7) {
    &:before {
      background-color: #2b52c6;
      top: 50px;
      left: 14px;
    }
  }
  &:nth-child(8) {
    &:before {
      background-color: #8366af;
      top: 45px;
      left: 10px;
    }
  }
}

接下来,为每个点点设置不同的延迟(由小到大):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
div {
  animation: roller 1.2s ease-in-out infinite;
  &:nth-child(1) {
    animation-delay: -0.036s;
  }
  &:nth-child(2) {
    animation-delay: -0.072s;
  }
  &:nth-child(3) {
    animation-delay: -0.108s;
  }
  &:nth-child(4) {
    animation-delay: -0.144s;
  }
  &:nth-child(5) {
    animation-delay: -0.18s;
  }
  &:nth-child(6) {
    animation-delay: -0.216s;
  }
  &:nth-child(7) {
    animation-delay: -0.252s;
  }
  &:nth-child(8) {
    animation-delay: -0.288s;
  }
}

现在,八个点点就排着队转起来了。

最后介绍一个不同阶段使用不同animation-timing-function效果的 loading。

HTML 结构:

1
<div class="disk" title="disk"></div>

html 结构很简单,只有一个disk圆盘元素。

从效果图可以看出,圆盘元素旋转了很多圈,但是旋转速度有很明显的快慢的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@keyframes disk {
  0%,
  100% {
    animation-timing-function: cubic-bezier(0.5, 0, 1, 0.5);
  }
  0% {
    transform: rotateY(0deg);
  }
  50% {
    transform: rotateY(1800deg);
    animation-timing-function: cubic-bezier(0, 0.5, 0.5, 1);
  }
  100% {
    transform: rotateY(3600deg);
  }
}

disk动画分三阶段:初始阶级,50%旋转 1800°=5 圈,100%旋转 3600°=10 圈。每个阶段有自己的animation-timing-function,可以使用 cubic-bezier 工具查看这两个函数的效果:cubic-bezier(0.5, 0, 1, 0.5)cubic-bezier(0, 0.5, 0.5, 1),前五圈由慢到快,后五圈由快到慢。

1
2
3
.disk {
  animation: disk 2.4s infinite;
}

利用animation可以实现很多有趣的 loading 效果,更多可以点击看效果

https://codepen.io/pennySU/pen/deLZrG/

  1. 动画弹跳

上面提到过hover on and hover offtransition,其实,hover on时定义animation也可以覆盖transition的效果,同时hover off是依然可以展示transition设置的动效:

1
2
3
4
5
6
7
8
9
10
11
.mask {
  transform: translateY(-200px);
  opacity: 0;
  transition: all 0.3s ease-out 0.5s;
}
.mask:hover {
  opacity: 1;
  transform: translateY(0px);
  transition-delay: 0s;
  animation: bounceY 0.9s linear;
}

.mask鼠标移入hover时,设置transition要执行动效的初始状态:opacity: 1;transform: translateY(0px);;,并执行animation动画;鼠标移出时,执行transition动效。

  1. backwards

文字的效果使用了mask-image属性,顾名思义,使图片作为元素的蒙版图层,很神奇的属性,张鑫旭大漠都有相应的文章。

这里主要想说一说backwards的作用:

1
2
3
4
5
6
span {
  color: #444;
  text-shadow: 0 0 2px #444, 1px 1px 4px rgba(0, 0, 0, 0.7);
  -webkit-mask-image: url(https://tympanus.net/Tutorials/TypographyEffects/images/mask2.png);
  animation: sharpen 0.6s linear backwards;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@keyframes sharpen {
  0% {
    opacity: 0;
    color: transparent;
    text-shadow: 0 0 100px #444;
  }
  90% {
    opacity: 0.9;
    color: transparent;
    text-shadow: 0 0 10px #444;
  }
  100% {
    opacity: 1;
    color: #444;
    text-shadow: 0px 0px 2px #444, 1px 1px 4px rgba(0, 0, 0, 0.7);
  }
}

在动画延迟期间,保存动画第一帧的样式。如果不设置backwards,文字在动画开始前将保持默认状态,即color 、text-shadow 、mask-image共同作用的状态(非隐藏),而不是效果图中开始时隐藏的状态。设置了backwards之后,会在延迟期间保持 0% 时设置的状态。

animation-name

动画名字,由@keyframes定义的动画序列。

animation-duration

动画的周期时长。

1
2
3
#box {
  animation-duration: 1s, 120ms;
}

animation-timing-function

每个关键帧周期动画执行的节奏。取值可见上面的transition-timing-function,此外,还有一个frames()属性:

  1. frames(2) 将按照给定的数值分成几个相等长度的时间。

来看一下steps()frames()的区别:

帧定时函数和步进定时函数的区别是,帧定时函数会在闭区间[0,1]之间按输入的数值平均分成若干份。这个特性在循环播放的动画中,第一帧和最后一帧执行的时间一样时很适用。

animation-delay

动画从应用在元素到开始的时间。

定义一个负值会让动画立即开始,但是动画会从动画序列的某处开始,如,设-1s,动画会从动画序列的第 1 秒位置处立即开始。

1
2
3
#box {
  animation-delay: 2s;
}

animation-iteration-count

动画运行的次数。

1
2
3
#box {
  animation-iteration-count: infinite | 2.3 | 0;
}

animation-direction

动画的播放顺序:

  1. normal 每个动画循环结束,动画重置到起点重新开始。
  2. alternate动画交替反向运行。
  3. reverse 每个周期有尾到头运行。
  4. alternate-reverse 第一次反向运行,第二次正向,后面依次循环。

点击看效果

animation-fill-mode

设置动画执行之前和之后如何给动画应用样式:

  1. none 动画执行前后不改变任何样式。
  2. forwards 动画完成后最后一帧的样式,最后一帧取决于animation-directionanimation-iteration-count
  3. backwards 在animation-delay时间内,动画的样式,保持第一帧的样式,取决于animation-direction
  4. both forwards 和 backwards都会执行。

点击看效果

animation-play-state

设置动画是执行还是暂停。

1
animation-play-state: running | paused;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值