CSS 过渡实战:状态变化、性能、事件与减少动态效果
本文目录
CSS transition 在属性值从一个状态变到另一个状态时绘制中间帧。它不会自动创建交互状态,也不会让任意属性都能平滑插值;先用普通 CSS 定义清晰的初始态和目标态,再为少量必要属性添加过渡。
显式指定属性与时长
.action {
transform: translateY(0);
opacity: 1;
transition: transform 180ms ease, opacity 180ms ease;
}
.action:hover,
.action:focus-visible {
transform: translateY(-2px);
}
.panel[data-open="false"] {
opacity: 0;
transform: translateY(0.5rem);
pointer-events: none;
}
transition 的属性顺序是 property、duration、timing-function、delay;每个属性都可分别控制。不要把 transition: all 当默认快捷方式:它会把意外变化也动画化,排查成本高,且可能动画布局相关属性。通常优先测量 transform 和 opacity;宽、高、位置、阴影等是否昂贵要结合实际页面和设备验证。
数值需要能够插值,或浏览器支持对应的离散行为。display、auto 高度等不能简单依赖传统数值过渡。折叠内容优先用正确的可访问状态和高度策略,保证隐藏内容不仍可聚焦;动画只是视觉反馈,不应决定权限或内容是否存在。
hover 抖动不是 transition 的通用故障
如果悬停目标本身移动出指针下方,hover 会立即取消,元素又移动回来,状态反复切换就会抖动。可把稳定区域作为触发容器、把移动效果施加到内部装饰层,或者重新检查几何关系和 pointer hit-test。移动端没有稳定 hover;关键操作必须通过 click、键盘焦点或显式按钮状态完成。
transitionend 不是可靠的唯一完成信号
transitionend 会按完成的属性触发,正向和反向切换都可能触发;取消、移除属性、display:none,或零时长时可能不触发。监听时检查 event.target 和 propertyName,并设置不会让交互永久卡住的状态回退。不要把它当成网络请求、动画完成或安全状态的唯一依据。
panel.addEventListener('transitionend', (event) => {
if (event.target !== panel || event.propertyName !== 'opacity') return;
panel.dataset.animationState = 'settled';
});
当状态由 React/Vue 或其他框架管理时,应让框架状态作为事实来源;动画事件只用于视觉层同步,并在卸载时清理监听。多个 CSS 属性会触发多个结束事件,过滤目标和属性名可避免重复收尾。
尊重减少动态效果偏好
缩放、平移和大面积运动可能让部分用户不适。用 prefers-reduced-motion 检查系统偏好,将非必要运动移除或缩短;保留即时的状态变化和焦点反馈。桌面、手机、键盘、触屏和系统减少动态效果设置都应纳入验收。
@media (prefers-reduced-motion: reduce) {
.action,
.panel {
transition-duration: 0.01ms;
scroll-behavior: auto;
}
}
验收清单
- 过渡是否列出需要变化的属性,而非不加区分地使用 all?
- 动画是否让内容跳动、遮挡、无法点击或影响布局?
- hover、键盘焦点、触屏点击的交互结果是否一致?
- 监听器是否过滤目标与属性,并能处理 transitioncancel/无事件路径?
- 减少动态效果偏好下是否仍能理解状态,且无需等待动画才能继续操作?
参考:MDN 使用 CSS transitions、MDN transitionend、MDN prefers-reduced-motion、web.dev 高性能 CSS 动画。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。