第八章 · 8.3 节
animation 与 @keyframes
transition 只能描述"从一个状态到另一个状态"的两点式过渡,而 animation 配合 @keyframes 可以定义任意数量的中间关键帧,还能无限循环、自动播放,无需任何交互触发——适合加载动画、注意力引导等场景。
与 transition 的区别
transition animation
触发方式 需要状态变化触发(如 :hover) 可自动播放,无需交互
关键帧数量 仅 2 个端点 任意多个(0%–100% 之间自由插入)
循环 不支持 支持 infinite 等循环次数控制
定义 @keyframes
@keyframes pulse {
0% { transform : scale(1) ; opacity : 1 ; }
50% { transform : scale(1.08) ; opacity : .85 ; }
100% { transform : scale(1) ; opacity : 1 ; }
}
百分比代表动画时间轴上的进度节点,也可以用 from / to 分别代替 0% / 100%。
animation 子属性
属性 作用
animation-name 引用的 @keyframes 名称
animation-duration 单次动画时长
animation-timing-function 缓动曲线,同 transition
animation-delay 开始前的延迟
animation-iteration-count 播放次数,infinite 为无限循环
animation-direction normal / alternate(往返播放)等
animation-fill-mode 动画前后的状态如何呈现,见下节
.badge {
animation : pulse 1.6s ease-in-out infinite ;
}
fill-mode 与初始/结束状态
默认情况下,动画播放结束后元素会"跳回"未应用动画时的原始样式;animation-fill-mode 可以让它保留在关键帧定义的状态:
取值 行为
none(默认) 动画前后都不应用关键帧样式
forwards 播放结束后保持最后一帧的样式
backwards 在 delay 等待期间就提前应用第一帧的样式
both forwards + backwards 同时生效
.enter {
animation : fade-up .4s ease-out both ;
}
@keyframes fade-up {
from { opacity : 0 ; transform : translateY(12px) ; }
to { opacity : 1 ; transform : translateY(0) ; }
}
实战:加载骨架屏
用渐变背景配合 background-position 动画,是"骨架屏加载态"最经典的实现方式:
.skeleton {
background : linear-gradient(90deg, #e7e8e1 25%, #f4f5f0 37%, #e7e8e1 63%) ;
background-size : 400% 100% ;
animation : shimmer 1.4s ease infinite ;
}
@keyframes shimmer {
0% { background-position : 100% 0 ; }
100% { background-position : 0 0 ; }
}
← 8.2 transition 过渡 9.1 aspect-ratio 与 object-fit →
Chapter 8 · Section 8.3
animation and @keyframes
transition can only describe a two-point change from one state to another, while animation combined with @keyframes can define any number of intermediate keyframes, loop indefinitely, and play automatically with no interaction required — ideal for loading animations, attention-guiding effects, and similar scenarios.
How animation Differs from transition
transition animation
Trigger Needs a state change to trigger (e.g. :hover) Can play automatically, no interaction needed
Keyframes Only 2 endpoints Any number (insert freely between 0%–100%)
Looping Not supported Supports iteration control such as infinite
Defining @keyframes
@keyframes pulse {
0% { transform : scale(1) ; opacity : 1 ; }
50% { transform : scale(1.08) ; opacity : .85 ; }
100% { transform : scale(1) ; opacity : 1 ; }
}
Percentages mark progress points on the animation timeline; from / to can also be used in place of 0% / 100%.
animation Sub-properties
Property Purpose
animation-name The @keyframes name it references
animation-duration Duration of a single iteration
animation-timing-function Easing curve, same as transition
animation-delay Delay before it starts
animation-iteration-count Number of plays; infinite loops forever
animation-direction normal / alternate (plays back and forth), etc.
animation-fill-mode How the state before and after the animation is shown, see next section
.badge {
animation : pulse 1.6s ease-in-out infinite ;
}
Live preview: continuous pulse
fill-mode and Initial/End States
By default, when an animation finishes the element snaps back to its original style as if the animation never applied; animation-fill-mode lets it keep the state defined by the keyframes:
Value Behavior
none (default) Applies keyframe styles neither before nor after the animation
forwards Keeps the last frame's style after the animation ends
backwards Applies the first frame's style early, during the delay wait
both forwards + backwards take effect together
.enter {
animation : fade-up .4s ease-out both ;
}
@keyframes fade-up {
from { opacity : 0 ; transform : translateY(12px) ; }
to { opacity : 1 ; transform : translateY(0) ; }
}
In Practice: Loading Skeleton Screens
Animating background-position with a gradient background is the classic way to build a skeleton loading state:
.skeleton {
background : linear-gradient(90deg, #e7e8e1 25%, #f4f5f0 37%, #e7e8e1 63%) ;
background-size : 400% 100% ;
animation : shimmer 1.4s ease infinite ;
}
@keyframes shimmer {
0% { background-position : 100% 0 ; }
100% { background-position : 0 0 ; }
}
← 8.2 transition 9.1 aspect-ratio and object-fit →