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) 判断
  • 最佳实践:用工具函数封装,统一处理降级逻辑
相关推荐
AiMan5 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真5 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment5 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan5 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么5 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模
上海懒图科技6 小时前
工厂厂区电子地图定位导航:厂区人车精准定位,安全合规双保障
前端·arcgis·vue
西安小哥6 小时前
端侧跑大模型,真正的门槛不在参数量:一次 596 秒到 10 秒的压缩路径复盘
前端·人工智能
陈随易6 小时前
Cloudflare 出钱,Vite 团队挑人,44 个维护者分 30 万美元
前端·后端·程序员
恋猫de小郭7 小时前
Flutter THLC 的 WebView 滚动终于从 70 FPS 提升到 120 FPS
android·前端·flutter
严肃小白兔8 小时前
TanStack Router 更新构建工具链:Node.js 兼容性、路由分割与前端工程实践
前端·node.js·状态模式