CSS animation 属性是 animation-name,animation-duration, animation-timing-function,animation-delay,animation-iteration-count,animation-direction,animation-fill-mode 和 animation-play-state 属性的一个简写属性形式。
| 值 | 描述 |
|---|---|
| animation-name | 规定需要绑定到选择器的 keyframe 名称。 |
| animation-duration | 规定完成动画所花费的时间,以秒或毫秒计。 |
| animation-timing-function | 规定动画的速度曲线。 |
| animation-delay | 规定在动画开始之前的延迟。 |
| animation-iteration-count | 规定动画应该播放的次数。 |
| animation-direction | 规定是否应该轮流反向播放动画。 |
| animation-fill-mode | 设置CSS动画在执行之前和之后如何将样式应用于其目标。 |
| animation-play-state | 定义一个动画是否运行或者暂停。 |
接下来我们来细细学习一下这些属性的妙用。
@keyframes
与 transition 相比,@keyframes 通过定义关键帧来控制动画的效果。
- from/0% 表示动画的第一帧,也就是动画的起始状态。这里要与元素本身的状态区别。
- to/100% 表示动画的最后一帧,动画结束时的状态,也要与元素本身的状态区别。
- X%(0<= X <= 100),表示动画 X% 的动画状态。
animation-name 和 animation-duration
animation-name 和 animation-duration 分别表示我们要使用的动画 keyframe 的名称,以及动画运行的时间。
<style>
.circle{
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
animation-name: move;
animation-duration: 1s;
}
@keyframes move {
to{
transform: translateX(400px);
}
}
</style>
<div class="circle"></div>
我们定义了小圆球的动画名称是 move,同时设置了动画运行时间是 1s。
animation-timing-function
animation-timing-function 定义了动画运行速度曲线,默认值是 ease.
| 值 | 描述 |
|---|---|
| linear | 动画从头到尾的速度是相同 |
| ease | 默认。动画以低速开始,然后加快,在结束前变慢。 |
| ease-in | 动画以低速开始。 |
| ease-out | 动画以低速结束。 |
| ease-in-out | 动画以低速开始和结束。 |
| cubic-bezier(n,n,n,n) | 在 cubic-bezier 函数中自己的值。可能的值是从 0 到 1 的数值。 |
我们定义了 6 个小圆球,从上到下分别用linear、ease、ease-in、 ease-out、ease-in-out、cubic-bezier(.17,.67,1,-0.11)表示其运行速度。我们可以在cubic-bezier.com/#.17,.67,.8… 这里自定义自己的贝塞尔曲线。
animation-delay
可以用来控制动画延迟多久执行。如果是正数 1s,表示延迟 1s 才开始动画;如果是负数 -1s,则不会延迟,相当于提前执行动画,动画的位置从动画执行1s的位置开始算。
延迟执行
<style>
.circle{
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
animation-name: move;
animation-duration: 2s;
animation-timing-function: linear;
}
@keyframes move {
to{
transform: translateX(400px);
}
}
.div2{
animation-delay: 1s;
}
</style>
<div class="circle"></div>
<div class="circle div2"></div>
提前执行
<style>
.circle{
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
animation-name: move;
animation-duration: 2s;
animation-timing-function: linear;
}
@keyframes move {
to{
transform: translateX(400px);
}
}
.div2{
animation-delay: -1s;
}
</style>
<div class="circle"></div>
<div class="circle div2"></div>
animation-iteration-count
定义了动画播放的次数,默认值为1,表示动画只播放一次。
- 可以取 infinite 表示无数次;
- 可以取正数;正整数和正小数。小数定义循环,来播放动画周期的一部分:例如,0.5 将播放到动画周期的一半。不可为负值。
animation-direction
animation-direction用来控制动画播放的方向。
- 默认 normal 从 @keyframes 定义的 0%(from) 到 100%(to) 播放的。
- alternate 表示第一次 0%(from) 到 100%(to) ;第二次从 100%(to) 到 0%(from) 播放;第三次 0%(from) 到 100%(to) ... 依次循环。
- reverse 与 normal 方向相反;
- alternate-reverse 与 reverse 方向相反。
| 值 | 描述 |
|---|---|
| normal | 每个循环内动画向前循环,换言之,每个动画循环结束,动画重置到起点重新开始,这是默认属性。 |
| alternate | 动画交替反向运行,反向运行时,动画按步后退,同时,带时间功能的函数也反向,比如,ease-in 在反向时成为ease-out。计数取决于开始时是奇数迭代还是偶数迭代 |
| reverse | 反向运行动画,每周期结束动画由尾到头运行。 |
| alternate-reverse | 反向交替, 反向开始交替 |
我们定义了4个小球演示 :
<style>
.circle{
width: 40px;
height: 40px;
border-radius: 50%;
background-color: red;
animation-name: move;
animation-duration: 2s;
animation-timing-function: linear;
}
@keyframes move {
to{
transform: translateX(400px);
}
}
.div2{
animation-direction: alternate;
animation-iteration-count: infinite;
}
.div3{
animation-direction: reverse;
}
.div4{
animation-direction: alternate-reverse;
animation-iteration-count: infinite;
}
div+div{
margin-top: 10px;
}
</style>
<div class="circle div1" style="margin-top: 100px;"></div>
<div class="circle div2"></div>
<div class="circle div3"></div>
<div class="circle div4"></div>
第一个小球和第二个动画的播放方向是从 from 到 to; 但是由于第二个小球的动画次数是无数次,所以会交替播放:从左到右、从右到左,从左到右...依次循环。
第三个小球和第四个小球的播放方向是从 to 到 from;由于第四个小球的动画次数是无数次,同第二个类似,会交替播放动画。
animation-fill-mode
可以用来设置动画播放开始播放前的状态以及动画播放结束的状态。
| 值 | 描述 |
|---|---|
| none | 动画效果 @keyframes 中第一帧和最后一帧不会保留在元素上面。这个也是默认取值 |
| forwards | 动画效果 @keyframes 中最后一帧会保留在元素上面 |
| backwards | 动画将在应用于目标时立即应用第一个关键帧中定义的值 |
| both | 动画将遵循forwards和backwards的规则,从而在两个方向上扩展动画属性。 |
利用 forwards 实现进度条
<style>
div{
margin-top: 200px;
margin-left: 40px;
}
.process{
width: 400px;
height: 10px;
border: 1px solid #ccc;
box-sizing: content-box;
position: relative;
}
.process::after{
content: "";
height: 10px;
display: inline-block;
background-color: red;
position: absolute;
top: 1px;
left: 0px;
animation-name: loading;
animation-duration: 3s;
animation-timing-function: linear;
animation-fill-mode: forwards;
}
@keyframes loading{
0%{
width: 0;
}
50%{
width: 200px;
}
100%{
width: 400px;
}
}
</style>
<div class="process"></div>
animation-fill-mode: forwards; 来表示动画结束的状态会被保留在元素上面。
backwards
在《一个不安分的箭头引发的思考(JS动画实现方式对比)》 juejin.cn/post/690703… 文章中 5个小箭头本身是 opacity:0;隐藏的,最后动画执行完毕后利用了 animation-fill-mode: forwards; 最后让5个小箭头处于显示状态。
我们也可以反过来,5个小箭头刚开始处于显示状态,设置一个动画初始值为隐藏,再利用 animation-fill-mode: backwards; 在动画执行前让箭头保持第一帧的状态。也可以实现哦~大家可以试一下,这里不再赘述。
steps 逐帧动画
animation-timing-function: steps(number, start/end);
- number是数字,表示将 动画关键帧之间 (0% 到 25%之间)设置为 number 步执行;
- 第二个参数表示动画第一帧(0%)是如何执行的。
start表示直接跳过第一帧(跳过0%),保持第一帧的结束状态;end表示保持第一帧的开始状态。 steps(n,start)可以简单理解为从第二个开始,steps(n,end)从第一个开始。- www.cnblogs.com/zx0423/p/13…
<style>
.wrap{
width: 200px;
height: 50px;
display: flex;
margin-top: 20px;
position: relative;
}
.item{
width: 50px;
height: 50px;
box-sizing: content-box;
border-top: 1px solid black;
border-bottom: 1px solid black;
border-right: 1px solid black;
background-color: #f1c40f;
line-height: 50px;
text-align: center;
color: white;
}
.item:first-child{
border-left: 1px solid black;
}
.move1{
width: 50px;
height: 50px;
background-color: red;
animation-name: move;
animation-duration: 4s;
animation-timing-function: steps(1, start);
animation-iteration-count: infinite;
position: absolute;
left: 0;
top: 1px;
}
.move2{
width: 50px;
height: 50px;
background-color: red;
animation-name: move;
animation-duration: 4s;
animation-timing-function: steps(1, end);
animation-iteration-count: infinite;
position: absolute;
left: 0;
top: 1px;
}
@keyframes move{
0%{
transform: translate(0px);
}
25%{
transform: translate(50px);
}
50%{
transform: translate(100px);
}
75%{
transform: translate(150px);
}
to{
transform: translate(200px);
}
}
</style>
</head>
<body>
<div class="wrap">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="move1"></div>
</div>
<div class="wrap">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="move2"></div>
</div>
</body>
可以看到 animation-timing-function: steps(1, start); 的执行效果是 0% 到 25%、25% 到 50%、50% 到 75% 、75% 到 100% 直接需要 1 步动画完成,并且第一帧 0% 从结束状态开始;animation-timing-function: steps(1, end); 第一帧 0% 从开始状态开始;
补充一个知识点:step-start 效果等于 steps(1,start) ,step-end 效果等同于 steps(1,end)。
轮播图
<style>
.swipe{
height: 100px;
width: 150px;
overflow: hidden;
}
.wrap{
height: 100px;
width: 150px;
white-space: nowrap;
font-size: 0;
animation-name: move;
animation-duration: 4s;
animation-timing-function: steps(1, end);
animation-iteration-count: infinite;
}
/* 鼠标悬浮暂停 */
.wrap:hover{
animation-play-state: paused;
}
.item{
width: 150px;
height: 100px;
color: white;
line-height: 100px;
text-align: center;
font-size: 18px;
display: inline-block;
}
.red{
background-color: #34495e;
}
.green{
background-color: #27ae60;
}
.yellow{
background-color: #9b59b6;
}
.blue{
background-color: #e74c3c;
}
@keyframes move{
0%{
transform: translate(0);
}
25%{
transform: translate(-150px);
}
50%{
transform: translate(-300px);
}
75%{
transform: translate(-450px);
}
100%{
transform: translate(-600px);
}
}
</style>
<div class="swipe">
<div class="wrap">
<div class="item red">1</div>
<div class="item green">2</div>
<div class="item yellow">3</div>
<div class="item blue">4</div>
</div>
</div>
发光的点
主要利用 box-shadow
<style>
.circle{
width: 14px;
height: 14px;
border-radius: 50%;
background-color: yellow;
animation: shrink 1s alternate infinite;
}
@keyframes shrink{
to{
/* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */
box-shadow: 0 0 14px 3px yellow;
}
}
</style>
<div class="wrap">
<div class="circle"></div>
</div>
圆圈loading
<style>
.circle{
stroke-dasharray: 157;
animation: loading 2s linear;
}
@keyframes loading{
0%{
stroke-dashoffset: 157;
}
50%{
stroke-dashoffset: 80;
}
100%{
stroke-dashoffset: 0;
}
}
</style>
<div class="wrap">
<svg viewBox="0 0 100 100" width="100" height="100">
<circle cx="50" cy="50" r="25" stroke="#F1C40F"
class="circle"
stroke-width="5" stroke-linecap="round" fill="none"/>
</svg>
</div>
补充一些 svg 知识:
- viewBox 用来控制画板的位置和大小;用法要设置4个值:
viewbox = "x, y, width, height"; - stroke-dasharray 设置的是圆弧的样式,这里取了圆的周长:2 * π * r ≈ 157;然后利用 stroke-dashoffset 偏移一点点的出现圆弧。
<style>
.circle1{
transform-origin: center center;
animation: strokeCircle1 1s linear infinite forwards, rotateCircle 2s linear infinite forwards;
}
.circle2{
transform-origin: center center;
animation: strokeCircle2 1s linear infinite forwards, rotateCircle 2s linear infinite forwards;
}
@keyframes strokeCircle1 {
0%{
stroke-dasharray: 10 150;
}
50%{
stroke-dasharray: 30 130;
}
100%{
stroke-dasharray: 50 110;
}
}
@keyframes strokeCircle2 {
0%{
stroke-dasharray: 10 150;
}
50%{
stroke-dasharray: 30 130;
}
100%{
stroke-dasharray: 50 110;
}
}
@keyframes rotateCircle{
from{
transform: rotate(0deg);
}
to{
transform: rotate(360deg);
}
}
</style>
<div class="wrap">
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="25" stroke="#F1C40F"
class="circle1" stroke-dasharray="10 150"
stroke-width="4" stroke-linecap="round" fill="none"/>
<circle cx="50" cy="50" r="25" stroke="#7F8C8D"
stroke-dashoffset="78" stroke-dasharray="10 150"
class="circle2"stroke-width="4" stroke-linecap="round" fill="none"/>
</svg>
</div>
www.jianshu.com/p/4422c05ff…
www.cnblogs.com/daisygogogo…
音符loading
<style>
.wrap, .bottom-wrap{
display: flex;
}
.item{
margin-left: 5px;
position: relative;
width: 15px;
height: 0;
}
.item::after{
content: "";
display: inline-block;
position: absolute;
bottom: 0;
width: 15px;
height: 50px;
background-color: crimson;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.item::before{
content: "";
display: inline-block;
position: absolute;
top: 0;
width: 15px;
height: 50px;
background-color: crimson;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
.wrap .item:nth-child(1)::after{
animation: loading 2s infinite;
}
.wrap .item:nth-child(2)::after{
animation: loading 2s infinite 0.2s;
}
.wrap .item:nth-child(3)::after{
animation: loading 2s infinite 0.4s;
}
.wrap .item:nth-child(4)::after{
animation: loading 2s infinite 0.6s;
}
.wrap .item:nth-child(5)::after{
animation: loading 2s infinite 0.8s;
}
.wrap .item:nth-child(1)::before{
animation: loading 2s infinite;
}
.wrap .item:nth-child(2)::before{
animation: loading 2s infinite 0.2s;
}
.wrap .item:nth-child(3)::before{
animation: loading 2s infinite 0.4s;
}
.wrap .item:nth-child(4)::before{
animation: loading 2s infinite 0.6s;
}
.wrap .item:nth-child(5)::before{
animation: loading 2s infinite 0.8s;
}
@keyframes loading {
0%{
height: 50px;
}
50%{
height: 5px;
}
100%{
height: 50px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="wrap">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</body>
感谢
如果本文有帮助到你的地方,记得点赞哦,这将是我坚持不断创作的动力~