资讯动态

浏览器原生 View Transitions API:零库实现丝滑页面过渡

发布时间:2026/10/6 7:37:06 来源:尧图企业网站定制
View Transitions 是什么传统实现页面过渡的方式javascript // ❌ 旧方式手动操作 DOM代码复杂 function navigate(to) { // 1. 截图当前页面 const screenshot await html2canvas(document.body); // 2. 导航到新页面 await fetchPage(to); // 3. 使用 GSAP/Framer Motion 做动画 gsap.fromTo(screenshot, { opacity: 1 }, { opacity: 0, duration: 0.3 } ); }2024 年正式标准化的View Transitions API让浏览器原生支持// ✅ 新方式浏览器内置简洁优雅 document.startViewTransition(() { // 更新 DOM updateTheDOM(); });核心优势性能浏览器底层优化60fps 流畅简单几行代码实现复杂动画跨页面MPA多页应用也能有 SPA 体验灵活CSS 自定义过渡效果核心 API 速览基础用法// 最简单的过渡 document.startViewTransition(() { // 这里的 DOM 变化会被自动捕捉为过渡动画 document.body.innerHTML newContent; });浏览器会自动捕获当前页面状态旧视图执行你的 DOM 更新函数捕获新页面状态新视图使用默认的淡入淡出动画过渡CSS 自定义动画/* 默认过渡淡入淡出 */ ::view-transition-old(root) { animation: fade-out 0.3s ease-out; } ::view-transition-new(root) { animation: fade-in 0.3s ease-in; } keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } /* 滑动过渡 */ ::view-transition-old(root) { animation: slide-out 0.5s ease-in-out; } ::view-transition-new(root) { animation: slide-in 0.5s ease-in-out; } keyframes slide-out { to { transform: translateX(-100%); } } keyframes slide-in { from { transform: translateX(100%); } }实战 1跨页面导航过渡MPA多页应用场景传统 MPA 跳转是白屏闪烁现在可以丝滑过渡// navigation.js // 拦截所有链接点击 document.addEventListener(click, async (e) { const link e.target.closest(a); if (!link || link.origin ! location.origin) return; e.preventDefault(); // 开始视图过渡 const transition document.startViewTransition(async () { // 获取新页面内容 const response await fetch(link.href); const html await response.text(); const parser new DOMParser(); const doc parser.parseFromString(html, text/html); // 更新页面保留当前 document替换内容 document.title doc.title; document.body.innerHTML doc.body.innerHTML; // 更新 URL history.pushState(null, , link.href); }); await transition.ready; }); // 处理浏览器前进后退 window.addEventListener(popstate, () { document.startViewTransition(() { location.reload(); // 或使用缓存的页面内容 }); });不同页面指定不同过渡效果// 根据页面类型选择动画 function getTransitionType(from, to) { if (to.includes(/product/)) return slide-left; if (from.includes(/product/)) return slide-right; return fade; } const type getTransitionType(location.pathname, link.href); document.documentElement.style.setProperty(--transition-type, type); // CSS 根据变量选择动画 ::view-transition-old(root) { animation-name: var(--transition-type)-out; }实战 2列表排序动画过去实现列表重排动画需要 FLIP 技术现在浏览器自动处理!-- 图片画廊 -- div classgallery idgallery div classcard styleview-transition-name: photo-1 img srccat.jpg alt猫 p可爱的猫/p /div div classcard styleview-transition-name: photo-2 img srcdog.jpg alt狗 p忠诚的狗/p /div !-- 更多卡片 -- /div div classfilters button onclicksort(date)按日期/button button onclicksort(name)按名称/button button onclicksort(size)按大小/button /div// 排序函数 function sort(criteria) { const gallery document.getElementById(gallery); const cards Array.from(gallery.children); // 开始视图过渡 document.startViewTransition(() { // 排序并重新插入 DOM cards.sort((a, b) { // 根据 criteria 排序逻辑 return compareCards(a, b, criteria); }); // 重新挂载浏览器会自动计算位置差并动画 cards.forEach(card gallery.appendChild(card)); }); }浏览器会自动记录每个元素的起始位置计算排序后的新位置使用硬件加速动画平滑移动列表项独立过渡/* 每个卡片有自己的 view-transition-name */ .card:nth-child(1) { view-transition-name: item-1; } .card:nth-child(2) { view-transition-name: item-2; } /* ... 或使用 JavaScript 动态设置 */ /* 独立的过渡动画 */ ::view-transition-group(item-1), ::view-transition-group(item-2) { animation-duration: 0.5s; } /* 图片使用不同的动画 */ ::view-transition-old(item-1 img), ::view-transition-new(item-1 img) { animation: scale-bounce 0.6s ease; } keyframes scale-bounce { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } }实战 3共享元素过渡类似 Android 的 Shared Element Transition!-- 列表页 -- div classproduct-list a href/product/123 classproduct-card idproduct-123 img srcshoe.jpg alt运动鞋 styleview-transition-name: product-image-123 h3 styleview-transition-name: product-title-123专业跑鞋/h3 p styleview-transition-name: product-price-123¥899/p /a /div!-- 详情页 -- div classproduct-detail img srcshoe.jpg alt运动鞋 styleview-transition-name: product-image-123 h1 styleview-transition-name: product-title-123专业跑鞋/h1 span styleview-transition-name: product-price-123¥899/span !-- 新元素淡入 -- p classdescription styleview-transition-name: product-desc 采用最新缓震科技... /p /div关键两页中相同view-transition-name的元素会被浏览器识别为同一个元素自动执行变形动画。/* 共享元素从卡片位置变形到详情位置 */ ::view-transition-group(product-image-123) { animation-duration: 0.5s; animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } /* 新元素描述从下方滑入 */ ::view-transition-new(product-desc) { animation: slide-up 0.4s ease-out 0.2s both; } keyframes slide-up { from { opacity: 0; transform: translateY(30px); } }与框架集成React/VueReact 集成// hooks/useViewTransition.ts import { useCallback, useTransition } from react; export function useViewTransition() { const [isPending, startTransition] useTransition(); const navigateWithTransition useCallback( (updateFn: () void) { if (!document.startViewTransition) { // 降级直接更新 startTransition(updateFn); return; } document.startViewTransition(() { startTransition(updateFn); }); }, [startTransition] ); return { navigateWithTransition, isPending }; } // 使用示例 function ProductList() { const [products, setProducts] useState([]); const { navigateWithTransition } useViewTransition(); const handleSort (criteria: string) { navigateWithTransition(() { setProducts(prev [...prev].sort(/* ... */)); }); }; return ( button onClick{() handleSort(price)}按价格排序/button div classNamegrid {products.map(p ( ProductCard key{p.id} product{p} style{{ viewTransitionName: product-${p.id} }} / ))} /div / ); }Vue 集成script setup import { ref, nextTick } from vue; const items ref([/* ... */]); async function sortItems() { // Vue 3 的 nextTick 配合 View Transition if (document.startViewTransition) { await document.startViewTransition(async () { items.value.sort(/* ... */); await nextTick(); // 等待 DOM 更新 }).ready; } else { items.value.sort(/* ... */); } } /script template button clicksortItems排序/button TransitionGroup namelist div v-foritem in items :keyitem.id :style{ viewTransitionName: item-${item.id} } {{ item.name }} /div /TransitionGroup /templateNext.js App Router 集成// app/layout.tsx import { ViewTransitions } from next-view-transitions; export default function RootLayout({ children }) { return ( ViewTransitions html body{children}/body /html /ViewTransitions ); } // app/page.tsx import { Link } from next-view-transitions; export default function Page() { return ( Link href/about classNamebutton 关于我们 {/* 自动处理过渡动画 */} /Link ); }性能优化与最佳实践1. 限制同时动画的元素数量/* 同时最多 10 个元素做动画其余的立即切换 */ media (prefers-reduced-motion: no-preference) { ::view-transition-group(*:nth-child(n11)) { animation-duration: 0s; } }2. 避免布局抖动// ❌ 不要这样在 transition 中读取布局 document.startViewTransition(() { updateDOM(); const height element.offsetHeight; // 强制同步布局 }); // ✅ 正确先读取再启动 transition const height element.offsetHeight; // 读取 document.startViewTransition(() { updateDOM(); // 只写入 });3. 处理长动画/* 给用户跳过动画的选择 */ media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation-duration: 0.01s !important; } } /* 或者提供跳过按钮 */ .skip-transition::view-transition-group(*) { animation-duration: 0s; }4. 调试技巧// 监听过渡事件 document.addEventListener(transitionstart, (e) { console.log(Transition started:, e.target); }); // 检查 View Transition 伪元素 // 在 DevTools Elements 面板查看 // ::view-transition // ::view-transition-group(root) // ::view-transition-image-pair(root) // ::view-transition-old(root) // ::view-transition-new(root)浏览器支持与降级方案当前支持情况2026年浏览器版本单页过渡跨页导航Chrome126✅✅Edge126✅✅Firefox预览版Safari18渐进增强策略// 工具函数安全使用 View Transition export function withViewTransition(updateFn, fallbackFn) { if (document.startViewTransition) { return document.startViewTransition(updateFn); } else { // 降级直接执行或使用传统动画库 updateFn(); return fallbackFn?.(); } } // 使用 import gsap from gsap; function animateReorder(items) { withViewTransition( () reorderDOM(items), // 主逻辑 () gsap.to(.item, { /* 降级动画 */ }) // 降级 ); }CSS 降级/* 现代浏览器View Transition */ supports (view-transition-name: test) { .card { view-transition-name: var(--transition-id); } } /* 旧浏览器使用传统 transform */ supports not (view-transition-name: test) { .card { transition: transform 0.3s; } .card:hover { transform: scale(1.05); } }总结View Transitions API 标志着 Web 动画进入新纪元方案复杂度性能适用场景CSS Transition低高简单状态变化View Transitions中极高页面级、列表级过渡GSAP/Framer高高复杂时间轴动画Canvas/WebGL极高极高游戏、3D 场景何时使用 View Transitions✅ MPA 想要 SPA 体验✅ 列表重排、网格布局变化✅ 跨页面共享元素动画❌ 复杂时间轴动画仍用 GSAP❌ 需要 IE 支持的项目2026 年这是每个前端都应该掌握的基础技能

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑