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) 判断
  • 最佳实践:用工具函数封装,统一处理降级逻辑
相关推荐
fatcoder1 小时前
玩转Nginx 09 — 运维排障:三场"火灾"实战演练
前端·后端·nginx
李高钢2 小时前
WPF MVVM Light(三):RelayCommand 命令与 Messenger 消息
前端·c#·wpf
lichenyang4532 小时前
Socket.IO 原理与技术选型
前端
qq21084629532 小时前
在python中什么是 self 和 cls?
开发语言·前端·python
我会冲击波2 小时前
vibe coding 一个多月,我把 Claude Code + Pi 做成了桌面 IDE,还给它移植了 VS Code 的编辑体验
前端·javascript·后端
kyson_2 小时前
前端性能优化全链路实践指南:从网络、缓存到渲染与监测
前端
前端fighter2 小时前
线上崩溃?使用 TRAE Work 5分钟把混淆日志翻译成人话并输出复盘报告
前端·vue.js·程序员
网安蟹佬霸2 小时前
CTF Web方向解题全攻略:从信息收集到getshell(附实战payload与脚本)
android·前端·网络·安全·web安全·网络安全·网安
前端玩坑坑2 小时前
CSS Container Queries 容器查询入门教程
前端