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

5 阅读4分钟

View Transitions API 入门教程

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


一、为什么需要 View Transitions?

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

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

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

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

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

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

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

View Transitions API 的解决:

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


二、View Transitions vs CSS Transition

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

三、完整示例

3.1 效果对比

<!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 基本用法

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

4.2 执行流程

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

4.3 自定义过渡动画

修改动画时长:

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.7s;
}

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

/* 让旧视图向左滑出 */
::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 特性检测

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

5.2 封装为工具函数

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

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

六、浏览器兼容性

浏览器最低版本备注
Chrome115+✅ 完全支持
Edge115+✅ 完全支持
Firefox115+✅ 支持
Safari不支持❌ 需要 Polyfill 或降级

七、常见应用场景

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

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

7.2 图片画廊切换

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

7.3 列表项展开/收起

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) 判断
  • 最佳实践:用工具函数封装,统一处理降级逻辑