一、简介
CSS 制作 Web 动画有两种方式: 帧动画(Keyframe Animation)和过渡动画(Transition Animation)。针对不同的业务场景中,我们应该选择不同的动画方式,通常来说:对于交互元素,会使用过渡动画,而对于连续的装饰性元素,则应该使用帧动画。
本文章将会仔细讲解transition
过渡动画的相关知识,让你对其有一个深入的了解。
二、过渡动画
1、基本概念
默认情况之下,修改CSS中的样式属性,其样式的变化是瞬间发生的,这显然是十分生硬,不够自然的,用户体验不够友好。
<style>
.btn {
width: 100px;
height: 40px;
background: green;
}
.btn:hover {
background: yellow;
transform: translateY(10px);
}
</style>
<div class=btn>按钮</div>
为了让样式变化更加平滑自然,可以使用CSS 的过渡(transition
)特性,可以在元素的 A
状态(初始状态)和元素的 B
状态(目标状态)之间进行插值计算。这个插值计算是由浏览器自动完成的,它会根据元素的初始状态 A
和结束状态 B
之间创建“中间”状态。从而使元素从一种状态(A
)平滑过渡到另一种状态(B
)。
.btn {
width: 100px;
height: 20px;
background: green;
/* 增加过渡属性 */
transition: all 250ms linear;
}
页面效果对比:
2、过渡属性
① transition
该属性用来设置元素的过渡动画,是过渡属性的简写形式,属性值可以包含四部分transition-property
、transition-duration
、ransition-timing-function
和transition-delay
。
可以同时针对多条CSS属性设置多个属性值,属性值之间通过,
连接。
/* 设置一条属性的过渡动画 */
transition: transform 200ms ease;
/* 同时设置多条属性的过渡动画 */
transition: transform 200ms ease, color 200ms ease;
/* 全属性简写 */
transition: transform 400ms linear 0.5s allow-discrete;
② transition-property
该属性用于指定要实现过渡动画的CSS属性,通常为transition
中的第一个属性值,也可单独设置该属性。属性值可以为一个具体的CSS属性,如:margin
、background-color
等等;也可以为一个关键词all
,表示当前元素所有变化的属性都实现过渡。
/* 指定单条实现过渡动画的属性 */
transition-property: transform;
/* 指定多条实现过渡动画的属性 */
transition-property: transform, color;
③ transition-duration
该属性用于指定完成过渡动画所需的时间,通常为transition
中的第二个属性值,也可单独设置该属性。属性值为时间+单位
,单位为秒s
或毫秒ms
,针对不同的过渡可以设置不同的时间。
/* 指定所有过渡动画的时间 */
transition-duration: 0.2s;
/* 指定多个过渡动画的时间 按顺序与 transition-property 中的属性对应 */
transition-duration: 0.2s, 200ms;
④ ransition-timing-function
属性用于指定过渡动画执行的速度曲线,通常为transition
中的第三个属性值,也可单独设置该属性。常见属性值有:linear
、ease
(默认值)、ease-in
、ease-out
和 ease-in-out
。其次还有:steps()
或cubic-bezier()
(贝塞尔曲线函数)。
/* 指定所有过渡动画的速度曲线 */
transition-timing-function: ease-in-out;
/* 指定多个过渡动画的速度曲线 */
transition-timing-function: ease, steps(4);
属性值详解:
-
linear
表示匀速运动,速度曲线是一条直线。 -
ease
(默认值)表示慢-快-慢,初期速度很慢,然后先逐渐加速,再快速减速,最终缓慢结束。加速过程较缓,减速过程较快。 -
ease-out
表示减速运动,先快后慢,初期速度很快,然后逐渐减速,最终缓慢结束。 -
ease-in
表示加速运动,先慢后快,初期速度很慢,然后逐渐加速,最终快速结束。 -
ease-in-out
表示慢-快-慢,初期速度慢,然后逐渐加速,中期速度最快,然后逐渐减速,最终缓慢结束。加速过程和减速过程相当。 -
linear()
函数定义了一个分段线性函数,可以在其各个点之间线性插值,从而允许你模拟出更复杂的动画效果,比如弹跳和弹簧等效果。JS或SVG可以通过linear曲线生成器 生成相应的曲线参数。 -
steps()
函数定义了分步运动,其效果相当于逐步执行过渡动画,类似于帧动画,接受两个参数,第一个参数指定的是步数,第二个参数指定的是方向。第二个参数值可以是jump-start
、jump-end
、jump-none
、jump-both
、start
和end(默认值)
,其中start
和jump-start
表现行为一样,同样的end
和jump-end
表现行为一样。函数还有两个预定义的关键字:step-start
和step-end
。前者等同于steps(1, start)
,而后者等同于steps(1, end)
。
jump-start
表示第一步动画在开始时发生;jump-end
表示最后一步动画在结束时发生;jump-both
表示在 0% 和 100% 处均出现跳跃,相当于在动画过程中加上一步;表示两端均无跳跃,而是在 0% 处和 100% 处将值各保持 1/n 的时长。更多内容可以查看:easing-function
。 -
cubic-bezier()
用于定义贝塞尔曲线,贝塞尔曲线由 P0、P1、P2 和 P3 四个点进行定义。P0 和 P3 是曲线的起点和终点,在 CSS 中,这两个点是固定的,因为坐标是成比例。P0 为 (0, 0),代表初始时间和初始状态,P3 为 (1, 1),代表最终时间和最终状态。其余的中间点 P1(x1,y1)、P2(x2,y2) 是可以动态改变的两个点,对应 cubic-bezier(x1,y1,x2,y2) 中的四个参数,通过改变 P1、P2 两点的坐标值来动态生成的贝塞尔曲线表示动画中的速度变化。 具体的贝塞尔曲线很难直接书写出来,我们可以通过贝塞尔曲线生成器,来获取对应的曲线值。
在固定y的情况下,x越大运动越慢,在固定x情况下,y越大运动越快。y如果是负数,则元素会变小,y’如果大于1,则会变大,但最终还会恢复为1。
⑤ transition-delay
该属性用于设置在过渡动画被触发之后,在开始之执行前需要等待的时间,通常为transition
中的第四个属性值,默认值为0,单位为秒s
或毫秒ms
。属性值为正数时,会等待这段时间后再执行过渡动画;属性值为0或者负数时,则会立即执行过渡动画。该属性也可以作为一条单独的属性进行设置。
如果transition
中分开设置了多条属性的过渡,则transition-delay
也可以设置多个等待时间,会按照先后顺序一一与过渡动画对应。
/* 设置两条属性进行过渡 */
transition: transform 200ms ease, color 200ms ease;
/* 分别设置两条属性的延迟等待时间 */
transition-delay: 0.2s, 400ms;
⑥ transition-behavior(兼容性一般)
该属性用于设置离散属性的平滑过渡效果,属性值为normal(默认)
和allow-discrete(开启离散属性过渡)
,该属性可以作为transition
中的第五个属性值。但该属性兼容性不是很好,因此并不常用。
像display
等不连续、无中间状态的属性,被称为离散属性。本来这些属性都是无法设置过渡动画的,但在设置transition-behavior: allow-discrete;
,且同时与普通的连续属性一起实现过渡动画时,则会启动离散属性的过渡效果。但单独为离散属性实现过渡动画时,该属性不会起作用。
通常会将离散属性和连续属性的transition-duration
设置相同的值,其呈现的效果为:连续属性动画执行结束后,立即变更离散属性的状态。例如:结合opacity
和display
实现元素逐渐位移消失的效果:
<style>
.btn2 {
width: 100px;
height: 40px;
background: green;
margin-top: 30px;
opacity: 1;
display: block;
transition: opacity 500ms linear, display 500ms linear;
/* 开启离散属性的过渡 */
transition-behavior: allow-discrete;
}
.btn2-click {
opacity: 0;
display: none;
}
</style>
<div class="btn2">按钮2</div>
<script>
const btn2 = document.querySelector('.btn2');
btn2.addEventListener('click', () => {
btn2.classList.toggle('btn2-click');
})
</script>
3、可设置过渡的CSS属性
一般来说,只有在其起始状态和最终状态之间具有“中间状态”的属性才能设置过渡动画,也可以称这些属性为连续属性。例如:
- 变换属性:
transform
。 - 颜色属性:
color
、border-color
、background-color
等。 - 阴影属性:
box-shaow
、text-shadow
等。 - 长度和尺寸属性:
whidth
、height
等。 - 位置属性:
top
、left
、margin
、padding
等。 - 透明度属性:
opacity
。 - 显示/隐藏属性:
visibility
。 - 背景属性:
background-size
、background-position
。 - 滤镜属性:
filter
。 - 混合模式属性:
mix-blend-mode
、background-blend-mode
。 - 剪切和蒙版属性:
clip-path
、mask-size
等。
4、过渡动画的触发器
过渡动画关键点就是必须包含两个状态—开始状态和结束状态,而且在这两个状态中同一属性在样式上发生了变化。触发两种状态转换的节点,被称为触发器。
常见的触发器有:
-
悬停触发:鼠标悬停在元素上时触发过渡动画,通常使用
:hover
伪类选择器实现。 -
焦点触发:元素失去焦点时触发过渡动画,通常使用
:focus
、:focus-within
和:focus-visible
等伪类选择器实现。 -
锚点链接触发:锚链接元素被点击时触发过渡,通常使用
:target
伪类选择器实现。 -
激活状态触发:元素被点击并按住时触发过渡,通常使用
:active
伪类选择器实现。 -
表单状态触发:表单元素被选择时触发过渡(输入框、单选框等),通常使用:
checked
、:valid
、:invalid
、:required
等表单状态伪类选择器。 -
class类名变更触发:元素的class发生变化时,如果包含可过渡的属性,则会触发过渡。
5、触发和退出使用不同过渡效果
在过渡动画中,我们可以为进入和退出设置不同的的过渡效果,从而实现更加复杂的动画交互。
例如:可以使用:hover
作为触发器,实现进入和退出的不同过渡动画效果。
<style>
.btn {
width: 100px;
height: 40px;
/* 元素本身的过渡 默认在进入和退出时 都生效 */
transition: transform 200ms ease;
}
.btn:hover {
transform: translateY(10px);
/* 进入时的过渡 仅生效于进入动画 优先级高于元素本身的过渡 会进行覆盖 */
transition: transform 400ms linear;
}
</style>
</head>
<div class="btn">按钮</div
6、过渡相关事件
① transitionrun
该事件在过渡动画被触发后立即触发,即使过渡动画设置了transition-delay
属性,也不会影响该事件的执行。
如果过渡动画中涉及多个CSS属性的变更,则会一一触发多个该事件。
element.addEventListener("transitionrun", (event) => {});
② transitionstart
该事件在过渡动画实际开始执行时触发,如果过渡动画设置了transition-delay
属性,则该事件会在等待时间结束后再触发。如果未设置等待时间,则仍会在transitionrun
事件后触发。
如果过渡动画中涉及多个CSS属性的变更,则会一一触发多个该事件。
element.addEventListener("transitionstart", (event) => {});
③ transitionend
该事件在过渡动画执行结束后触发,如果在当前过渡动画结束之前,对应的过渡动画被取消,则该事件不会被触发。
如果过渡动画中涉及多个CSS属性的变更,则会一一触发多个该事件。
element.addEventListener("transitionend", (event) => {});
④ transitioncancel
该事件在过渡动画开始执行但又被取消后触发,过渡动画被取消的情况包含三种:transition-property
属性被修改、display
属性被设为none
和触发器停止触发(例如:鼠标移出hover动画元素)。
如果过渡动画中涉及多个CSS属性的变更,则会一一触发多个该事件。
element.addEventListener("transitioncancel", (event) => {});
7、过渡事件对象:
所有过渡事件的事件对象event
除了继承Event
的相关属性之外,还拥有三个特殊属性:
event.propertyName
(只读):表示当前过渡的CSS属性的名称字符串。event.elapsedTime
(只读):表示触发此事件时,过渡动画已经运行的时间,单位为秒(s)。event.pseudoElement
(只读):表示当前过渡动画的绑定元素是否为伪元素,如果是伪元素则值为::伪元素名称
,如果绑定的不是伪元素,则值为""
。
案例代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>过渡动画</title>
<style>
.btn {
width: 100px;
height: 40px;
background: green;
/* 元素本身的过渡 在进入和退出且无其他过渡时 都生效 */
transition: all 800ms ease;
}
.btn:hover {
background: yellow;
transform: translateY(10px);
/* 进入时的过渡 优先级高于元素本身的过渡 */
transition: all 400ms linear 2s allow-discrete;
}
</head>
<body>
<div class="btn">按钮</div>
<script>
const btn = document.querySelector('.btn');
btn.addEventListener('transitionrun', (event) => {
console.log('transitionrun---', event);
})
btn.addEventListener('transitionstart', (event) => {
console.log('transitionstart---', event);
})
btn.addEventListener('transitionend', (event) => {
console.log('transitionend---', event);
})
btn.addEventListener('transitioncancel', (event) => {
console.log('transitioncancel---', event);
})
</script>
</body>
</html>