transition、@keyframes animation 和 Hover.css
transition
Transitions enable you to define the transition between two states of an element. Different states may be defined using pseudo-classes like :hover or :active or dynamically set using JavaScript.
综上,transition 动效切换最常用的方式是用伪类(常用 :hover
)或者用 JS 动态添加
简单使用可参考 CSS3 过渡
transition 属性设置元素的过渡效果,四个简写属性为:(默认值 all 0 ease 0
)(其中前两个比较常用)
- transition-property(指定 transition 所作用的 CSS 属性,默认
all
全部) - transition-duration(指定效果完成时间,默认
0
表示无效果) - transition-timing-function(指定效果转速曲线,默认
ease
) - transition-delay(定义效果开始的时候,需要延迟多久开始,默认
0
不延迟)
最简 demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 100px;
height: 100px;
background-color: red;
transition: 1s;
}
.box:hover {
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
上面的 demo 所有的属性 transition-duration 都是 1s,如何同时指定多个 transition-property?
同时指定多个属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 100px;
height: 100px;
background-color: red;
/* 同时指定不同属性 */
transition: width 2s, height 2s, background-color 1s;
}
.box:hover {
width: 200px;
height: 200px;
background-color: yellow;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
用 JS 实现动效切换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 100px;
height: 100px;
background-color: red;
transition: 2s;
}
.larger {
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
document.querySelector('.box').addEventListener('click', () => {
document.querySelector('.box').classList.add('larger')
})
</script>
</body>
</html>
keyframes animation
简单使用可参考 CSS3 动画
@keyframes 规则是创建动画
@keyframes bg-color-change {
from {background: red;}
to {background: yellow;}
}
可以用百分比来规定变化发生的时间,或者用关键字 from
和 to
,等同于 0%
和 100%
@keyframes bg-color-change {
0% {background: red;}
50% {background: green;}
100% {background: yellow;}
}
用 @keyframes 创建完一个动画,需要把它绑定到一个选择器
最简 demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: red;
}
@keyframes bg-color-change {
from {background: red;}
to {background: yellow;}
}
.box:hover {
/* 绑定 @keyframes 到一个选择器 */
animation: bg-color-change 2s;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
@keyframes 所有动画属性:
- animation-name(规定 @keyframes 动画的名称)
- animation-duration(规定动画完成一个周期所需要的时间)
- animation-timing-function(规定动画的速度曲线,默认
ease
) - animation-delay(规定动画开始的延迟时间)
- animation-play-state(可设置
paused
暂停动画,默认running
) - animation-iteration-count(设置动画播放次数,默认
1
,常用设置infinite
表示无限循环) - animation-direction(定义是否循环交替反向播放动画)(常用设置
alternate
,即 1、3、5 等正向播放,2、4、6 等反向播放,多用于循环动画中) - animation-fill-mode(设置当动画开始前,或者结束后的样式)
其他的都比较好理解,这里重点说下 animation-fill-mode(更多可以参考 如何理解animation-fill-mode及其使用?)
看下这个例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: blue;
}
@keyframes bg-color-change {
from {background: red;}
to {background: yellow;}
}
.box.on {
/* 绑定 @keyframes 到一个选择器 */
animation: bg-color-change 2s;
animation-delay: 1s;
}
</style>
</head>
<body>
<div class="box on"></div>
</body>
</html>
我们发现动画开始时有一个 blue->red 的跳转,结束的时候有一个 yellow->blue 的跳转,我们可以设置动画开始前的颜色为 @keyframes 中 from 的样式(animation-fill-mode: backwards
),结束的颜色为 to 的样式(animation-fill-mode: forwards
),也可以同时设置两者(animation-fill-mode: both
)
注意如果样式是通过 hover 或者 JS 动态设置的,animation-fill-mode: backwards
的设置其实没啥用(因为不是直接的动画,所以初始的样式不可能用 @keyframes 中 from 的)
hover + animation-fill-mode
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: blue;
}
@keyframes bg-color-change {
from {background: red;}
to {background: yellow;}
}
.box:hover {
/* 绑定 @keyframes 到一个选择器 */
animation: bg-color-change 2s;
animation-delay: 1s;
animation-fill-mode: both;
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
JS + animation-fill-mode
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: blue;
}
@keyframes bg-color-change {
from {background: red;}
to {background: yellow;}
}
.box.on {
/* 绑定 @keyframes 到一个选择器 */
animation: bg-color-change 2s;
animation-delay: 1s;
animation-fill-mode: both;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
document.querySelector('.box').addEventListener('click', () => {
document.querySelector('.box').classList.add('on')
})
</script>
</body>
</html>
transition VS keyframes animation
- transition 只有两个状态:开始状态和结束状态;但 animation 可以有多个状态,有帧的概念,并且可以指定动画次数
- transition 需要借助别的方式来触发,比如 CSS 的状态选择器(如
:hover
)或借助 JS 触发;animation 可以自动触发
所以 keyframes animation > transition,所有 transition 的动画其实都能用 @keyframes 实现
实战
- animate.css(keyframes animation)
- Hover.css(transition + keyframes animation)
如果需要面试,可以考察下 Hover.css
先考察几个比较简单的动效:
- Fade(最基本的动效,背景色和字体颜色渐变)(考察基础的 transition)
- Grow(基础。考察
transform: scale(1.1)
) - Wobble Horizontal(左右快速移动,考察 @keyframes +
transform: translateX(8px)
)(因为从开始到结束并不是只有两个状态,所以需要用 @keyframes) - Buzz(和 Wobble Horizontal 类似,也是需要用到 @keyframes,并且是 translateX 和 rotate 属性一起作用,且设置 animation-iteration-count 为 infinite)
Sweep to Right
首先可以考察下这个蓝色背景色是如何加进去的?(用 ::before
或者 ::after
)
然后考查蓝色背景色位置是如何介于原来 box 和文字中间的?(需要设置 box 为一个新的堆叠上下文,详见 由 Sweep To Right 动效引发的对 z-index 的再度学习)
最后才是考察 transition 相关
一个简单实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
display: inline-block;
margin: 0.4em;
padding: 1em;
cursor: pointer;
background: #e1e1e1;
color: #666;
position: relative;
/* 这里主要为了产生一个层叠上下文 */
z-index: 0;
transition: 1s;
}
.container:hover {
color: white;
}
.container::after {
content: '';
position: absolute;
width: 0;
height: 100%;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: #2098D1;
z-index: -1;
transition: 1s;
}
.container:hover::after {
width: 100%;
}
</style>
</head>
<body style="padding: 200px">
<a class="container">
Hover me
</a>
</body>
</html>
以上实现是用 width 渐变来做的,也可以用 scale 做大小的渐变(注意需要设置 transform-origin: 0 50%
,默认是 (0, 0)
,在元素的左上角)
scale 实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
display: inline-block;
margin: 0.4em;
padding: 1em;
cursor: pointer;
background: #e1e1e1;
color: #666;
position: relative;
/* 这里主要为了产生一个层叠上下文 */
z-index: 0;
transition: 1s;
}
.container:hover {
color: white;
}
.container::after {
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: #2098D1;
transform-origin: 0 50%;
transform: scaleX(0);
z-index: -1;
transition: 1s;
}
.container:hover::after {
transform: scaleX(1);
}
</style>
</head>
<body style="padding: 200px">
<a class="container">
Hover me
</a>
</body>
</html>
其实修改 transform-origin
以及 transform
可以完成很多不同的渐变效果
Shutter In Horizontal / Shutter Out Horizontal
Shutter Out Horizontal 比较简单,其实就是 Sweep to Right 的变种(transform-origin: 50%
,毕竟是从中心开始变大)
Shutter Out Horizontal
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
display: inline-block;
margin: 0.4em;
padding: 1em;
cursor: pointer;
background: #e1e1e1;
color: #666;
position: relative;
/* 这里主要为了产生一个层叠上下文 */
z-index: 0;
transition: 1s;
}
.container:hover {
color: white;
}
.container::after {
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: #2098D1;
transform-origin: 50%;
transform: scaleX(0);
z-index: -1;
transition: 1s;
}
.container:hover::after {
transform: scaleX(1);
}
</style>
</head>
<body style="padding: 200px">
<a class="container">
Hover me
</a>
</body>
</html>
但是 Shutter In Horizontal 如何实现呢?如果还是将蓝色背景当作 ::after
的元素,可能就需要两个 box,我们可以反过来思考,将灰色背景当作 ::after
的元素,这个思路很巧妙
实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
display: inline-block;
margin: 0.4em;
padding: 1em;
cursor: pointer;
background-color: #2098D1;
color: #666;
position: relative;
/* 这里主要为了产生一个层叠上下文 */
z-index: 0;
transition: 1s;
}
.container:hover {
color: white;
}
.container::after {
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: #e1e1e1;
transform-origin: 50%;
transform: scaleX(1);
transition: 1s;
z-index: -1;
}
.container:hover::after {
transform: scaleX(0);
}
</style>
</head>
<body style="padding: 200px">
<a class="container">
Hover me
</a>
</body>
</html>
Rectangle In / Rectangle Out
先看 Rectangle Out,参考 Shutter Out Horizontal
Rectangle Out
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
display: inline-block;
margin: 0.4em;
padding: 1em;
cursor: pointer;
background: #e1e1e1;
color: #666;
position: relative;
/* 这里主要为了产生一个层叠上下文 */
z-index: 0;
transition: 1s;
}
.container:hover {
color: white;
}
.container::after {
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: #2098D1;
transform-origin: 50%;
transform: scale(0, 0);
z-index: -1;
transition: 1s;
}
.container:hover::after {
transform: scale(1, 1);
}
</style>
</head>
<body style="padding: 200px">
<a class="container">
Hover me
</a>
</body>
</html>
Rectangle In 参考 Shutter In Horizontal,将两个颜色颠倒,反向思考即可
Underline From Left / Underline From Center
其实和前面的没啥本质区别
Underline From Left
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
display: inline-block;
margin: 0.4em;
padding: 1em;
cursor: pointer;
background: #e1e1e1;
color: #666;
position: relative;
/* 这里主要为了产生一个层叠上下文 */
z-index: 0;
transition: 1s;
}
.container::after {
content: '';
position: absolute;
height: 5px;
right: 0;
left: 0;
bottom: 0;
background-color: #2098D1;
transform-origin: 0 50%;
transform: scaleX(0);
z-index: -1;
transition: 1s;
}
.container:hover::after {
transform: scaleX(1);
}
</style>
</head>
<body style="padding: 200px">
<a class="container">
Hover me
</a>
</body>
</html>
Underline From Center 无非是修改下 transform-origin: 50%