CSS 动画允许元素在一段时间内从一个状态平滑地过渡到另一个或多个状态,不需要 JavaScript。
CSS 动画由两部分组成:
@keyframes —— 定义动画过程animation 属性 —— 控制动画的播放方式@keyframes 规则定义动画的关键帧序列。
/* 基础语法 */
@keyframes animation-name {
from {
/* 起始状态 */
}
to {
/* 结束状态 */
}
}
/* 百分比语法 推荐 */
@keyframes animation-name {
0% {
/* 状态 */
}
50% {
/* 状态 */
}
100% {
/* 状态 */
}
}
/* 示例 */
@keyframes slideIn {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-30px);
}
60% {
transform: translateY(-15px);
}
}
@keyframes colorChange {
0% {
background-color: red;
}
33% {
background-color: yellow;
}
66% {
background-color: blue;
}
100% {
background-color: green;
}
}
Animation 属性简写语法:
.element {
animation: name duration timing-function delay iteration-count direction fill-mode play-state;
}
/* 简写 */
.box {
animation: move 2s ease-in-out 0s infinite alternate;
}
/* 单个属性写法 */
.box {
animation-name: move;
animation-duration: 2s;
animation-timing-function: ease;
animation-delay: 0s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-fill-mode: both;
animation-play-state: running;
}
animation-name指定要使用的@keyframes名称。
animation-name: slideIn;
animation-duration动画完成一个周期所需时间。
animation-duration: 2s; /* 2秒 */
animation-duration: 500ms; /* 500毫秒 */
animation-timing-function动画的速度曲线。
animation-timing-function: ease; /* 默认 */
animation-timing-function: linear; /* 匀速 */
animation-timing-function: ease-in; /* 慢开始 */
animation-timing-function: ease-out; /* 慢结束 */
animation-timing-function: ease-in-out; /* 慢开始和结束 */
animation-timing-function: cubic-bezier(0.1, 0.7, 1, 0.1); /* 自定义 */
animation-timing-function: steps(4, jump-start); /* 步进动画 */
animation-delay动画开始前的延迟时间。
animation-delay: 1s; /* 延迟1秒 */
animation-delay: -1s; /* 从第1秒开始 */
animation-iteration-count动画播放次数。
animation-iteration-count: 1; /* 播放1次 */
animation-iteration-count: 3; /* 播放3次 */
animation-iteration-count: infinite; /* 无限循环 */
animation-direction动画是否反向播放。
animation-direction: normal; /* 正常播放 */
animation-direction: reverse; /* 反向播放 */
animation-direction: alternate; /* 奇数次正向,偶数次反向 */
animation-direction: alternate-reverse; /* 奇数次反向,偶数次正向 */
animation-fill-mode动画执行前后如何应用样式。
animation-fill-mode: none; /* 默认,动画前后不应用任何样式 */
animation-fill-mode: forwards; /* 动画结束后保持最后一帧的样式 */
animation-fill-mode: backwards; /* 动画开始前应用第一帧的样式 */
animation-fill-mode: both; /* 同时应用forwards和backwards */
animation-play-state控制动画的播放状态。
animation-play-state: running; /* 正在播放 */
animation-play-state: paused; /* 暂停播放 */
/* 定义动画 */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 应用动画 */
.element {
animation: fadeInUp 1s ease-out 0.5s both;
}
/* 分开写法 */
.element {
animation-name: fadeInUp;
animation-duration: 1s;
animation-timing-function: ease-out;
animation-delay: 0.5s;
animation-fill-mode: both;
}
@keyframes loading {
0% {
transform: rotate(0deg);
width: 50px;
height: 50px;
}
25% {
background-color: #ff6b6b;
border-radius: 50%;
}
50% {
transform: rotate(180deg);
width: 80px;
height: 80px;
}
75% {
background-color: #4ecdc4;
border-radius: 10%;
}
100% {
transform: rotate(360deg);
width: 50px;
height: 50px;
}
}
.loader {
animation: loading 2s ease-in-out infinite alternate;
}
@keyframes move {
0% {
left: 0;
}
100% {
left: calc(100% - 50px);
}
}
@keyframes color {
0%,
100% {
background-color: red;
}
50% {
background-color: blue;
}
}
.box {
position: relative;
width: 50px;
height: 50px;
animation: move 3s linear infinite, color 1.5s ease-in-out infinite;
}
transform和opacity/* 性能好 */
@keyframes good-animation {
to {
transform: translateX(100px);
opacity: 0.5;
}
}
/* 性能差 */
@keyframes bad-animation {
to {
margin-left: 100px;
width: 200px;
}
}
will-change优化.element {
will-change: transform, opacity;
animation: myAnimation 1s;
}
.element {
transform: translateZ(0); /* 触发GPU加速 */
animation: myAnimation 1s;
}
// 开始/暂停动画
const element = document.querySelector(".element");
// 开始动画
element.style.animationPlayState = "running";
// 暂停动画
element.style.animationPlayState = "paused";
// 监听动画事件
element.addEventListener("animationstart", e => {
console.log("动画开始");
});
element.addEventListener("animationend", e => {
console.log("动画结束");
});
element.addEventListener("animationiteration", e => {
console.log("动画循环一次");
});
// 动态添加动画
element.style.animation = "fadeIn 1s forwards";
// 重置动画
element.style.animation = "none";
void element.offsetWidth; // 触发重排
element.style.animation = "fadeIn 1s forwards";
| 特性 | CSS Transition | CSS Animation |
|---|---|---|
| 触发方式 | 需要状态变化(hover、active 等) | 可以自动播放 |
| 复杂度 | 简单,两个状态之间 | 复杂,多关键帧序列 |
| 控制度 | 有限,只能控制起点和终点 | 完全控制每一帧 |
| 循环播放 | 不可以 | 可以(infinite) |
| 方向控制 | 只能正向 | 可以正向、反向、交替 |
| 暂停控制 | 有限 | 完全控制(paused/running) |
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.spinner {
animation: spin 1s linear infinite;
}
@keyframes shimmer {
0% {
background-position: -200px 0;
}
100% {
background-position: calc(200px + 100%) 0;
}
}
.skeleton {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200px 100%;
animation: shimmer 1.5s infinite linear;
}
@keyframes typing {
from {
width: 0;
}
to {
width: 100%;
}
}
@keyframes blink {
50% {
border-color: transparent;
}
}
.typewriter {
overflow: hidden;
border-right: 3px solid;
white-space: nowrap;
animation: typing 3.5s steps(40, end), blink 0.75s step-end infinite;
}
/* 前缀版本 */
@-webkit-keyframes fadeIn {
/* Webkit browsers */
}
@keyframes fadeIn {
/* Standard */
}
.element {
-webkit-animation: fadeIn 1s; /* Chrome, Safari */
animation: fadeIn 1s;
}