css 页面切换动画怎么做_使用 animation 配合状态类名

核心是用状态类名(如.page-enter-active/.page-leave-active)控制动画触发,配合animation-fill-mode: both、仅用opacity/transform等高性能属性,并严格管理类名增删时机与层叠上下文。

怎么用 animation 实现页面切换动画

核心是「状态类名控制动画触发」,不是靠 JS 直接调用 animate() 或操作 keyframes。浏览器对 class 切换的重绘更可控,也更容易和路由、组件生命周期对齐。

常见错误是把动画写在初始样式里(比如直接给 .pageanimation),结果一进页面就播,无法响应「进入/离开」两个方向。

  • 动画必须绑定在「带状态语义的类名」上,比如 .page-enter-active.page-leave-active
  • 进入和离开需分离定义:进入时加 .page-enter.page-enter-active,离开时加 .page-leave.page-leave-active
  • 务必设置 animation-fill-mode: both,否则动画结束瞬间样式会回退到初始值(比如 opacity 突然变 1)

@keyframes 里不要写 layout 触发属性

heighttopleft 这类会触发 Layout 的属性,在动画中会导致卡顿,尤其在低端设备或复杂 DOM 下。

优先用只触发 Composite 的属性:opacitytransformtranslateXscalerotate)。

@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(100%);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.page-enter-active {
  animation: slideInRight 0.3s ease-out;
  animation-fill-mode: both;
}

如何避免多个页面同时动画打架

当路由快速切换(比如连点两次导航),旧页面还没走完 leave 动画,新页面就进来了,容易出现层叠、错位、z-index 混乱。

  • 给容器加 position: relative 和统一 z-index,再用 transform: translateZ(0) 强制生成新层叠上下文
  • 离开动画结束后,JS 必须手动移除 .page-leave-active 类(CSS 不会自动清理)
  • 进入动画开始前,确保旧页面已移除 .page-enter-active,可用 getComputedStyle(el).animationName 检查是否还在播

React/Vue 中 class 切换时机很关键

不能等组件 mounteduseEffect 才加类 —— 那时 DOM 已渲染完毕,动画会漏掉第一帧。

正确做法是在「决定切换」的瞬间(如点击导航后、路由解析完成时)立刻添加 enter/leave 类,再让框架更新 DOM。

  • Vue:用 enter-from-class/leave-to-class 配合 appear,别手写 class 切换逻辑
  • React:用 useLayoutEffect 在 DOM 绘制前加类,比 useEffect 更稳
  • 纯 HTML + JS:监听 popstate 后立即操作 class,然后用 requestAnimationFrame 延迟一帧再更新内容
动画真正难的不是写 keyframes,而是 class 的增删节奏、DOM 生命周期的配合、以及多状态并存时的隔离处理。稍不注意,就会出现「动画播了一半页面没了」或者「新旧页面叠在一起动」。