Skip to content

View Transitions API:打造丝滑流畅的页面动画

约 1839 字大约 6 分钟

2025-07-27

在现代 Web 开发中,流畅的页面过渡效果能够显著提升用户体验。View Transitions API 是一个革命性的浏览器原生 API,它让创建复杂的页面过渡动画变得前所未有的简单。本文将带你从零开始,全面掌握这个强大的 API。

什么是 View Transitions API?

View Transitions API 是一个新的 Web 标准,它提供了一种声明式的方法来创建页面之间的平滑过渡动画。想象一下,当你在相册应用中切换图片时,图片会平滑地从一个位置过渡到另一个位置——View Transitions API 让这样的效果变得轻而易举。

核心优势

  • 简化复杂动画:以前需要大量 JavaScript 和 CSS 的动画,现在几行代码就能实现
  • 性能优化:浏览器原生支持,性能远超 JavaScript 实现的动画
  • 跨文档过渡:支持单页应用和多页应用中的页面过渡
  • 自动状态捕获:浏览器自动处理前后状态的快照

基础用法

1. 启用 View Transitions

要使用 View Transitions API,首先需要检查浏览器支持情况:

// 检查浏览器支持
if (document.startViewTransition) {
  // 浏览器支持 View Transitions API
}
else {
  // 降级方案
  console.log('View Transitions API 不被支持')
}

2. 基本页面过渡

最简单的用法是在页面导航时添加过渡效果:

// 拦截导航事件
document.addEventListener('click', (event) => {
  const link = event.target.closest('a')
  if (!link)
    return

  // 如果是站内链接
  if (link.href && link.origin === location.origin) {
    event.preventDefault()

    // 开始视图过渡
    document.startViewTransition(() => {
      // 导航到新页面
      location.href = link.href
    })
  }
})

3. 单页应用中的使用

在单页应用(SPA)中,View Transitions API 可以创建更精细的过渡效果:

// 假设我们有一个简单的 SPA 路由
async function navigateTo(url) {
  // 开始视图过渡
  const transition = document.startViewTransition(async () => {
    // 获取新内容
    const response = await fetch(url)
    const html = await response.text()

    // 更新页面内容
    document.body.innerHTML = html
  })

  // 等待过渡完成
  await transition.finished
  console.log('过渡完成!')
}

深入理解过渡过程

View Transitions API 的过渡过程分为几个关键阶段:

  • 捕获快照:浏览器捕获当前页面的快照
  • 更新 DOM:执行你提供的回调函数来更新页面
  • 捕获新快照:浏览器捕获更新后页面的快照
  • 执行动画:浏览器在两个快照之间执行过渡动画

自定义过渡动画

1. 使用 CSS 自定义动画

View Transitions API 的强大之处在于可以使用 CSS 完全自定义动画效果:

/* 为所有视图过渡设置基础样式 */
::view-transition-old(root) {
  animation: 0.5s ease-out both fade-out;
}

::view-transition-new(root) {
  animation: 0.5s ease-out both fade-in;
}

@keyframes fade-out {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(20px);
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

2. 为特定元素创建命名过渡

你可以为页面中的特定元素创建独立的过渡效果:

// 更新特定元素的过渡名称
function updateElementWithTransition(element, newContent) {
  // 为元素设置唯一的过渡名称
  element.style.viewTransitionName = 'special-element'

  document.startViewTransition(() => {
    element.innerHTML = newContent
  }).finished.then(() => {
    // 过渡完成后清除名称
    element.style.viewTransitionName = 'none'
  })
}

然后在 CSS 中定义这个命名过渡:

::view-transition-old(special-element) {
  animation: 0.3s both slide-out;
}

::view-transition-new(special-element) {
  animation: 0.3s both slide-in;
}

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

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

高级特性

1. 共享元素过渡

共享元素过渡是 View Transitions API 最强大的功能之一,它允许元素在不同页面间平滑移动:

// 为图片元素设置过渡名称
function setupImageTransitions() {
  const images = document.querySelectorAll('.gallery-image')

  images.forEach((img, index) => {
    // 为每个图片设置唯一的过渡名称
    img.style.viewTransitionName = `image-${index}`

    img.addEventListener('click', () => {
      // 在详情页使用相同的过渡名称
      document.startViewTransition(() => {
        // 导航到详情页
        showImageDetail(img.src, `image-${index}`)
      })
    })
  })
}

2. 控制过渡时序

你可以精确控制过渡的时序和分组:

::view-transition-group(special-element) {
  /* 控制整个过渡组的动画时长 */
  animation-duration: 0.8s;
}

::view-transition-image-pair(special-element) {
  /* 控制新旧图片对的隔离行为 */
  isolation: auto;
}

实际应用示例

1. 图片画廊

让我们创建一个完整的图片画廊过渡示例:

HTML
gallery.html
<div class="gallery">
  <img src="image1.jpg" class="gallery-item" data-id="1">
  <img src="image2.jpg" class="gallery-item" data-id="2">
  <img src="image3.jpg" class="gallery-item" data-id="3">
</div>

2. 列表到详情过渡

另一个常见的使用场景是列表项到详情页的过渡:

// 列表项点击处理
function setupListTransitions() {
  const listItems = document.querySelectorAll('.list-item')

  listItems.forEach((item, index) => {
    item.style.viewTransitionName = `item-${index}`

    item.addEventListener('click', () => {
      document.startViewTransition(async () => {
        // 显示详情
        await showItemDetail(item.dataset.id)

        // 在详情页设置过渡名称
        const detailElement = document.querySelector('.detail-content')
        detailElement.style.viewTransitionName = `item-${index}`
      })
    })
  })
}

性能优化和最佳实践

1. 性能考虑

性能提示

  • 避免过度使用:不是所有的页面变化都需要过渡效果
  • 注意内存使用:快照会占用内存,特别是在移动设备上
  • 测试降级方案:确保在不支持的浏览器中页面仍能正常工作

2. 降级方案

function safeViewTransition(updateCallback) {
  if (document.startViewTransition) {
    return document.startViewTransition(updateCallback)
  }
  else {
    // 直接执行更新,没有过渡效果
    updateCallback()
    return {
      finished: Promise.resolve(),
      ready: Promise.resolve(),
      updateCallbackDone: Promise.resolve()
    }
  }
}

// 使用安全的过渡函数
safeViewTransition(() => {
  // 更新页面内容
  updateContent()
})

3. 可访问性考虑

/* 为偏好减少动画的用户提供支持 */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

常见问题解答

Q: View Transitions API 支持哪些浏览器?

A: 目前 Chrome/Edge 111+ 和 Opera 98+ 支持,其他浏览器正在逐步支持中。

Q: 可以在 iframe 中使用吗?

A: 目前 iframe 中的 View Transitions 支持有限,建议在主文档中使用。

Q: 过渡过程中可以取消吗?

A: 是的,你可以使用 transition.skipTransition() 来取消进行中的过渡。

总结

View Transitions API 为 Web 开发带来了革命性的页面过渡体验。通过本文的学习,你应该已经掌握了:

  • 基础使用方法:如何使用 document.startViewTransition() 创建基本过渡
  • 自定义动画:通过 CSS 伪元素完全控制过渡效果
  • 高级特性:共享元素过渡、命名过渡等高级用法
  • 实际应用:在图片画廊、列表详情等场景中的具体实现
  • 最佳实践:性能优化、降级方案和可访问性考虑

参考