View Transitions API 入门教程,优雅过度

View Transitions API 入门教程

一句话理解:DOM 发生变化时,浏览器自动帮你做"截图过渡",让变化看起来平滑自然。


一、为什么需要 View Transitions?

场景:页面内容切换太生硬

想象一个常见的场景:点击按钮切换页面内容,旧内容瞬间消失,新内容突然出现,用户感觉很突兀。

css 复制代码
❌ 不使用 View Transitions:
   ┌─────────────┐      ┌─────────────┐
   │   方块A     │  →   │   方块A‑变色  │   (直接闪现,没有任何过渡)
   │  [蓝色]     │      │  [红色]      │
   └─────────────┘      └─────────────┘

✅ 使用 View Transitions:
   ┌─────────────
   │   方块A     │
   │  [蓝色]     │ ──► 慢慢淡出
   └─────────────┘
         │
         ▼
   ┌─────────────┐
   │  方块A‑变色  │ ◄── 慢慢淡入
   │  [红色]      │
   └─────────────┘

传统的 CSS transition 解决不了这个问题:

css 复制代码
/* 这只能对单个元素的属性变化做动画 */
.box {
  transition: background-color 0.5s;
}

当整个 DOM 结构(元素被替换或内容完全改变)发生变化时,CSS transition 无能为力。

View Transitions API 的解决:

浏览器在 DOM 变化前后各"截一张图",然后在两张截图之间做平滑过渡动画。


二、View Transitions vs CSS Transition

维度 CSS Transition / Animation View Transitions API
适用对象 单个元素的属性变化(如颜色、大小) 整个 DOM 的变化(元素替换、内容切换)
触发方式 CSS 属性变化自动触发 JavaScript 调用 startViewTransition()
动画内容 属性值的插值动画 新旧 DOM 截图之间的过渡动画
复杂度 简单,纯 CSS 即可 需要 JS 配合,但功能更强大
浏览器支持 全部支持 Chrome 115+、Edge 115+、Firefox 115+

三、完整示例

3.1 效果对比

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>View Transitions 使用 vs 不使用对比</title>
  <style>
    body {
      font-family: system-ui;
      padding: 24px;
      max-width: 700px;
    }

    .wrap {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 30px;
    }

    .panel {
      border: 1px solid #ccc;
      padding: 16px;
      border-radius: 8px;
    }

    .box {
      width: 180px;
      height: 180px;
      border-radius: 12px;
      display: grid;
      place-items: center;
      color: #fff;
      font-size: 20px;
      cursor: pointer;
      margin: 10px 0;
    }

    .blue { background: #2563eb; }
    .red { background: #dc2626; }

    /* ===== 自定义过渡动画时长 ===== */
    ::view-transition-old(root),
    ::view-transition-new(root) {
      animation-duration: 0.7s;
    }

    button {
      padding: 8px 14px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <h2>View Transitions 对比演示</h2>
  <div class="wrap">
    <!-- 不使用 ViewTransition:直接修改DOM,直接闪现 -->
    <div class="panel">
      <h4>❌ 不使用 ViewTransitions</h4>
      <div id="box1" class="box blue">方块A</div>
      <button id="btn1">切换颜色</button>
      <p>效果:直接瞬间闪变,没有动画</p>
    </div>

    <!-- 使用 ViewTransition:带平滑过渡动画 -->
    <div class="panel">
      <h4>✅ 使用 ViewTransitions</h4>
      <div id="box2" class="box blue">方块B</div>
      <button id="btn2">切换颜色</button>
      <p>效果:淡入淡出平滑过渡</p>
    </div>
  </div>

  <script>
    const box1 = document.querySelector('#box1');
    const box2 = document.querySelector('#box2');
    const btn1 = document.querySelector('#btn1');
    const btn2 = document.querySelector('#btn2');

    let state1 = true;
    let state2 = true;

    // --------------------------
    // 不使用 View Transitions
    // 直接修改 DOM,无任何过渡
    // --------------------------
    btn1.onclick = function () {
      state1 = !state1;
      if (state1) {
        box1.className = 'box blue';
        box1.textContent = '方块A';
      } else {
        box1.className = 'box red';
        box1.textContent = '方块A-变色';
      }
    };

    // --------------------------
    // 使用 View Transitions API
    // --------------------------
    btn2.onclick = function () {
      if (!document.startViewTransition) {
        // 浏览器不支持则降级直接修改DOM
        toggleBox2();
        return;
      }
      document.startViewTransition(toggleBox2);
    };

    function toggleBox2() {
      state2 = !state2;
      if (state2) {
        box2.className = 'box blue';
        box2.textContent = '方块B';
      } else {
        box2.className = 'box red';
        box2.textContent = '方块B-变色';
      }
    }
  </script>
</body>
</html>

3.2 效果对比

操作 不使用 View Transitions 使用 View Transitions
点击按钮 颜色和内容瞬间切换 旧内容淡出,新内容淡入
视觉感受 生硬、突兀 平滑、自然

四、核心 API 详解

4.1 基本用法

js 复制代码
// 最简形式:把 DOM 修改逻辑包在 startViewTransition 中
document.startViewTransition(() => {
  // 在这里修改 DOM
  updateDOM();
});

4.2 执行流程

sql 复制代码
用户点击按钮
     │
     ▼
┌─────────────────────────────────────────┐
│ document.startViewTransition(callback)  │
└─────────────────────────────────────────┘
     │
     ▼
┌─────────────────┐
│ ① 捕获旧快照    │  ← 浏览器截取当前 DOM 的"照片"
│    (old)        │
└─────────────────┘
     │
     ▼
┌─────────────────┐
│ ② 执行回调      │  ← 执行你的 DOM 修改代码
│    (callback)   │
└─────────────────┘
     │
     ▼
┌─────────────────┐
│ ③ 捕获新快照    │  ← 浏览器截取修改后的 DOM "照片"
│    (new)        │
└─────────────────┘
     │
     ▼
┌─────────────────┐
│ ④ 播放过渡动画  │  ← old 淡出 + new 淡入
│    (0.7s)       │
└─────────────────┘

4.3 自定义过渡动画

修改动画时长:

css 复制代码
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.7s;
}

修改动画类型(默认是淡入淡出):

css 复制代码
/* 让旧视图向左滑出 */
::view-transition-old(root) {
  animation: slide-out 0.7s ease-in-out;
}

/* 让新视图从右侧滑入 */
::view-transition-new(root) {
  animation: slide-in 0.7s ease-in-out;
}

@keyframes slide-out {
  to { transform: translateX(-100%); opacity: 0; }
}

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

五、降级策略

5.1 特性检测

js 复制代码
if (document.startViewTransition) {
  // 支持 View Transitions
  document.startViewTransition(updateDOM);
} else {
  // 不支持,直接修改 DOM
  updateDOM();
}

5.2 封装为工具函数

js 复制代码
function withTransition(callback) {
  if (document.startViewTransition) {
    return document.startViewTransition(callback);
  }
  // 不支持时直接执行
  callback();
  return null;
}

// 使用方式
btn.onclick = () => {
  withTransition(() => {
    // 修改 DOM 的逻辑
    toggleContent();
  });
};

六、浏览器兼容性

浏览器 最低版本 备注
Chrome 115+ ✅ 完全支持
Edge 115+ ✅ 完全支持
Firefox 115+ ✅ 支持
Safari 不支持 ❌ 需要 Polyfill 或降级

七、常见应用场景

7.1 单页应用(SPA)页面切换

js 复制代码
// 路由切换时添加过渡
router.beforeEach((to, from, next) => {
  if (document.startViewTransition) {
    document.startViewTransition(() => {
      next();
    });
  } else {
    next();
  }
});

7.2 图片画廊切换

js 复制代码
function showImage(index) {
  withTransition(() => {
    gallery.innerHTML = `<img src="${images[index]}">`;
  });
}

7.3 列表项展开/收起

js 复制代码
function toggleItem(id) {
  withTransition(() => {
    const item = document.querySelector(`[data-id="${id}"]`);
    item.classList.toggle('expanded');
  });
}

八、与 CSS Transition 的对比总结

场景 推荐方案 原因
单个元素的 hover 效果 CSS Transition 简单,无需 JS
颜色/大小等属性变化 CSS Transition 浏览器自动插值
整个 DOM 内容切换 View Transitions 浏览器自动截图过渡
页面路由切换 View Transitions 提供类似原生 App 的过渡体验
需要复杂控制 CSS Animation + JS 完全自定义动画

九、总结

  • View Transitions API = 浏览器自动帮你做"新旧截图过渡"
  • 核心方法 :document.startViewTransition(callback)
  • 自定义动画 :通过 ::view-transition-old() 和 ::view-transition-new() 伪元素
  • 必须做降级 :Safari 不支持,需要 if (document.startViewTransition) 判断
  • 最佳实践:用工具函数封装,统一处理降级逻辑
相关推荐
Lsx_8 分钟前
微信支付接入全流程:JSAPI支付、小程序支付与H5支付
前端·javascript·全栈
OpenTiny社区25 分钟前
React 正式登场!GenUI SDK v1.4.0 三框架渲染、出码与 Agent 生态重磅升级~
前端·ai编程
试图让你心动34 分钟前
【无标题】
前端·javascript·vue.js
Hilaku37 分钟前
为什么每个前端都应该拥有一个自己的独立博客?
前端·javascript·程序员
燕落南枝40 分钟前
CSS 后代选择器与子代选择器:从入门到实战
前端·css
Amos_Web44 分钟前
Rspack 源码解析(二十八):HtmlRspackPlugin 如何把模板变成带资源标签的最终产物
前端
马可家的菠萝1 小时前
个人知识库怎么建?从一个正在学的技术主题开始
前端·笔记·知识管理·个人知识库
几何心凉1 小时前
端到端具身交互智能正式上线:让 AI 通过屏幕和机器人,真正走进现实世界
前端·人工智能·实时互动·机器人·交互
tryCbest2 小时前
Vue3——第 6 篇:事件处理与表单绑定——v-on 与 v-model
前端·javascript·vue.js
恋猫de小郭2 小时前
Flutter 的文字为什么比 SwiftUI 更细?问题主要在 Skia 的 256 项查找表里
android·前端·flutter