View Transitions API 实战 2026:用浏览器原生能力做流畅的页面过渡
从列表点击进入详情,图片像被一只无形的手放大、平移、落位;返回时它又缩回列表原位。这种过去要依赖重量级动画库、还要手动对齐位置的共享元素过渡,如今浏览器原生就能完成。2026 年,View Transitions API 已在所有主流浏览器全面可用,跨文档过渡更被纳入 Interop 2026 互操作性计划。本文系统实战 View Transitions:单页应用同文档过渡的基本原理、view-transition-name 命名与共享元素、自定义关键帧动画、列表到详情的经典场景、多页应用跨文档过渡与 pageswap/pagereveal 事件、React/Vue 框架集成、无障碍与降级,以及性能边界。
今日技术简讯
📰 技术简讯 · 2026-10-12
今日聚合 6 条热门技术内容(中文素材优先)。
🤖 AI / LLM
1. 谷歌 Gemini 4「Argon」即将公开发布,内部测试更强版本「Carbon」
- 链接:http://m.toutiao.com/group/7694804779515625999/
- 来源:IT之家
- 摘要:据商业内幕报道,谷歌即将正式发布新一代旗舰 Gemini 4「Argon」,同时内部已在测试代码能力更强的后续版本「Carbon」,早期员工反馈其编程表现对标竞品顶级代码模型;旗舰模型竞争进入长周期软件工程的正面较量阶段。
2. Google DeepMind 开源多模态嵌入模型 EmbeddingGemma 2
- 链接:https://www.marktechpost.com/2026/10/06/google-deepmind-releases-embeddinggemma-2-a-740m-open-multimodal-embedding-model-built-on-gemma-4/
- 来源:MarkTechPost
- 摘要:Google DeepMind 发布 EmbeddingGemma 2,约 7.4 亿参数,可将文本、代码、图像、视频与音频映射到统一向量空间,采用 Apache 2.0 许可;多模态检索与 RAG 应用首次获得可自由商用的轻量级统一嵌入底座。
🎨 前端 / Web
3. Ant Design 6.5 发布:用 DESIGN.md 适配 AI 设计工具,包体积大幅瘦身
- 链接:https://github.com/ant-design/ant-design/releases
- 来源:Ant Design
- 摘要:Ant Design 6.5 引入定义视觉语言的 DESIGN.md 以适配 AI 设计工具,压缩后包体积显著下降,并为多个主流 AI 与社交平台新增内置图标;组件库的交付物正在从"组件代码"扩展到"机器可读的设计规范"。
4. Linear 完成超千个 PR 的迁移:从 styled-components 全面转向 StyleX
- 链接:https://www.infoq.com/React/news/
- 来源:InfoQ
- 摘要:Linear 完成 React 应用从 styled-components 到 Meta StyleX 的迁移,涉及上千个 PR,核心动机是性能与更严格的组件边界;运行时 CSS-in-JS 的主线程开销被编译期确定的样式取代,导航流畅度获得改善。
⚙️ 后端 / 架构
5. Redis 开源版 8.10:紧凑哈希让同构数据只存一次字段名
- 链接:https://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/release-notes/redisce/redisos-8.10-release-notes/
- 来源:Redis
- 摘要:Redis 开源版 8.10 引入紧凑哈希编码,结构相同的哈希键只存储一份字段名,配合高吞吐批量导入命令显著降低内存占用;同时增强集合基数运算与 Stream 读取上限控制,并修复多项安全问题,大规模对象存储的内存性价比进一步提升。
🚀 独立开发 / OPC
6. 两天做出的 AI 小游戏上线一个月吸引数十万玩家
- 链接:https://indiefront.cn/articles/cmuwhonxl000e9zqc118wc8n3/
- 来源:独立开发前线
- 摘要:独立开发者用 AI 在两天内完成小红书小游戏「小喵钓鱼」,上线一个月吸引大量玩家、日新增数千。案例的启示并非"做游戏很容易",而是 AI 把原型到上架的周期压缩到极致后,独立开发者的核心竞争力转向选题、平台理解与快速试错的节奏。
数据来源:掘金 / InfoQ 中文 / 即刻 / 少数派 / HN 采集日期:2026-10-12 (UTC+8)
今日深度文
View Transitions API 实战 2026:用浏览器原生能力做流畅的页面过渡
优秀的界面动画从来不是装饰,而是空间关系的说明。点击列表里的一张卡片进入详情,如果详情页是"唰"地一下整体替换,用户需要重新定位自己在哪里;如果卡片上的图片平滑放大、移动并落位到详情页的大图位置,用户一眼就能理解"我从哪里来、这个页面和刚才是什么关系"。这就是共享元素过渡(shared element transition)的价值。在很长一段时间里,实现它需要 FLIP 技术、手动测量位置、引入动画库;而现在,浏览器把这件事做成了原生能力——View Transitions API。2026 年它已在所有主流浏览器全面可用,连传统多页站点也能通过跨文档过渡获得同样的体验。
一、它到底解决了什么:从"整页替换"到"连续空间"
没有过渡时,DOM 更新是瞬间发生的:旧状态一帧消失,新状态下一帧出现,两者之间没有任何视觉关联。
无过渡的状态切换:
第 N 帧:列表(卡片是小图)
第 N+1 帧:详情(大图、正文) ← 用户大脑需要重新建立空间认知
View Transition 做的事:
第 N 帧:对旧状态截图(old snapshot)
中间帧:浏览器自动生成从旧位置到新位置的动画
第 N+1 帧:新状态(new snapshot)就位
→ 旧视图"变形"为新视图,元素的对应关系被视觉传达
浏览器在过渡期间做了三件开发者过去要手动完成的苦活:
① 快照:分别捕获过渡前、后的页面视觉状态。
② 命名配对:按 view-transition-name 找到"旧状态的 A 元素"
与"新状态的 A 元素",判定为同一元素的两个形态。
③ 自动补间:对配对元素的位置、尺寸、内容自动生成过渡,
开发者只需用 CSS 描述"想要什么动画"。
关键认知:**你操作的仍然是普通 DOM,View Transitions 只负责"状态 A 到状态 B 怎么演",不改变任何渲染逻辑。**这也是它比动画库方案轻得多的根本原因。
二、两种模式:同文档过渡与跨文档过渡
View Transitions 有两个适用场景,API 形态不同,先建立全局认知:
模式一:同文档过渡(same-document,SPA 经典场景)
页面不刷新,由 JS 改变 DOM(标签切换、模态框、路由切换)。
入口:document.startViewTransition(() => { 更新DOM })
支持:全主流浏览器。
模式二:跨文档过渡(cross-document,MPA 经典场景)
真实的页面跳转(a 标签、表单提交、前进后退),
旧文档与新文档是两份独立 HTML。
入口:CSS @view-transition 声明启用 +
pageswap / pagereveal 事件做精细控制。
状态:全主流浏览器已支持,互操作性持续打磨中。
跨文档过渡有几个硬性前提,先记在心里,后面细说:只作用于同源导航、导航过程不能包含跨域重定向、新旧两个文档都要通过 CSS 主动选择启用。
三、最小可用例子:一个标签切换
先看同文档模式的完整最小例子。HTML 是两个普通的面板与切换按钮:
<button id="toggle">切换视图</button>
<div id="panelA" class="panel">面板 A:概览数据</div>
<div id="panelB" class="panel" hidden>面板 B:详细列表</div>
JS 只做一件事:把 DOM 更新包进 startViewTransition。注意回调必须同步反映新状态——浏览器在回调执行后捕获新快照。
const panelA = document.querySelector("#panelA");
const panelB = document.querySelector("#panelB");
document.querySelector("#toggle").addEventListener("click", () => {
// 把普通的 DOM 切换交给过渡 API 包裹
document.startViewTransition(() => {
panelA.hidden = !panelA.hidden;
panelB.hidden = !panelB.hidden;
});
});
不加任何 CSS,浏览器会给整个页面一个默认的淡入淡出。想自定义,就操作过渡期间自动生成的伪元素树:
过渡期间浏览器构建的伪元素层级:
::view-transition ← 覆盖层根
└─ ::view-transition-group(root) ← 布局/尺寸动画的容器
├─ ::view-transition-old(root) ← 旧状态快照(淡出)
└─ ::view-transition-new(root) ← 新状态快照(淡入)
root 是默认名称;设置了 view-transition-name 的元素
会各自生成一组 group/old/new。
自定义动画就是给这些伪元素写普通的 CSS 动画:
/* 让整页默认过渡变成轻微上移 + 淡入,更克制更快 */
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.25s;
animation-timing-function: ease;
}
@keyframes fade-up {
from {
opacity: 0;
transform: translateY(12px);
}
}
::view-transition-new(root) {
animation-name: fade-up;
}
到这里你已经拥有了一个零依赖、由合成线程驱动的页面切换动画。
四、共享元素:用 view-transition-name 给元素"配对"
整页淡入淡出只是开胃菜,真正强大的是共享元素。给过渡前后"同一个东西"赋予相同的 view-transition-name,浏览器就会让它从旧形态平滑变形到新形态。
经典场景:列表卡片缩略图 → 详情页主图。
/* 列表中的卡片图片 */
.card-cover {
view-transition-name: hero-photo;
}
/* 详情页的大图:同名,即建立配对 */
.detail-hero {
view-transition-name: hero-photo;
}
配合 JS 的状态更新(这里以客户端渲染列表/详情为例):
/**
* 从列表进入详情:更新 DOM 的动作包进过渡
* 同名元素 hero-photo 会从卡片位置放大到主图位置
*/
function openDetail(postId) {
document.startViewTransition(() => {
renderDetail(postId); // 同步切换到详情视图
});
}
/**
* 从详情返回列表:同名元素自动"缩回"原位
*/
function backToList() {
document.startViewTransition(() => {
renderList();
});
}
浏览器自动补间了位置(translate)、尺寸(width/height)和宽高比变化,开发者完全不需要 getBoundingClientRect 手算。这正是过去 FLIP 库最繁琐的部分。
**命名有一条铁律:同一时刻,一个 view-transition-name 在页面中只能对应一个被渲染的元素。**名字重复会导致过渡被跳过,因为浏览器无法判断该配对谁:
常见翻车点:
× 给列表所有卡片图片都写死 view-transition-name: item-photo
→ 一屏几十个同名元素,过渡直接失效。
√ 只给"被点击的那张卡片"动态设置名字,
其余卡片保持 none,详情页大图用同一个名字。
列表场景的正确做法是点击时才命名:
/**
* 点击卡片:仅为被点击卡片指定共享名,保证全局唯一
*/
function onCardClick(card, postId) {
card.querySelector(".card-cover").style.viewTransitionName = "hero-photo";
document.startViewTransition(() => renderDetail(postId));
}
返回列表时也要清理,避免下一屏残留同名元素:
/**
* 返回后清除共享名,恢复列表多卡片共存状态
*/
function backToList() {
document.startViewTransition(() => renderList());
// 新状态已无详情大图;列表图片统一不设共享名,避免重名
}
五、自定义过渡手感:分组、旧层、新层分别控制
默认动画之外,可以分别控制容器(位置/尺寸)与新旧两层(内容交叉淡入)。一个带轻微缩放、内容交叉淡化的详情打开动画:
/* 容器层:负责位置与尺寸的平滑移动 */
::view-transition-group(hero-photo) {
animation-duration: 0.32s;
animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}
/* 旧内容快速淡出,新内容稍晚淡入,形成柔和交叉 */
::view-transition-old(hero-photo) {
animation: hero-out 0.32s ease both;
}
::view-transition-new(hero-photo) {
animation: hero-in 0.32s ease 0.06s both;
}
@keyframes hero-out {
to { opacity: 0; }
}
@keyframes hero-in {
from { opacity: 0; }
}
除了共享的主图,让其余内容(正文、标题)分别有节奏地进场,可以给它们也起不同名字:
.detail-title { view-transition-name: detail-title; }
.detail-body { view-transition-name: detail-body; }
/* 正文做轻微上浮,与主图移动错开几十毫秒 */
::view-transition-new(detail-body) {
animation: body-in 0.4s ease 0.08s both;
}
@keyframes body-in {
from { opacity: 0; transform: translateY(10px); }
}
设计上的建议:**过渡时长控制在两三百毫秒、位移幅度克制、缓动用 ease-out 类曲线。**动画是在帮用户理解空间,不是在表演——过长、过炫的过渡会让高频操作显得拖沓。
六、跨文档过渡:多页站点也能拥有原生动画
对传统 MPA(包括 Next.js 静态导出、Astro、纯静态博客这类每次跳转都是真实 HTML 文档的站点),跨文档过渡是 2026 年最值得关注的能力。启用方式意外地简单——新旧两个页面都加上同一段 CSS 即表示"我同意参与过渡":
/* 列表页与详情页都要写:对同源导航启用跨文档过渡 */
@view-transition {
navigation: auto;
}
仅此一行,浏览器就会在页面跳转时复用 View Transition 的快照机制:默认给整页一个淡入淡出。要做共享元素,依然是老办法——两个文档里的对应元素使用同一个 view-transition-name:
/* 列表页 index.html */
.card-cover { view-transition-name: hero-photo; }
/* 详情页 post.html —— 同名即配对,跨文档同样有效 */
.detail-hero { view-transition-name: hero-photo; }
跨文档的唯一命名问题更微妙:列表页有几十张卡片,而详情页只有一张大图。解决方法是只让"当前被点击卡片"携带名字——点击跳转前用 JS 动态设置:
/**
* 列表页:点击卡片时,给该卡片写入共享名,
* 随后让浏览器正常跳转到详情页
*/
document.querySelectorAll(".card").forEach((card) => {
card.addEventListener("click", () => {
document.querySelectorAll(".card-cover").forEach((img) => {
img.style.viewTransitionName = "none";
});
card.querySelector(".card-cover").style.viewTransitionName = "hero-photo";
});
});
需要在导航发生时做更精细的控制(按前进/后退方向给不同动画),使用两个生命周期事件:
/**
* 旧文档即将离开:可通过 event.viewTransition 定制
*/
window.addEventListener("pageswap", (event) => {
if (!event.viewTransition) return;
// navigation.activationType 可区分 traverse(前进/后退)等类型
});
/**
* 新文档即将呈现:在这里给不同进入方向的过渡加类名
*/
window.addEventListener("pagereveal", (event) => {
if (!event.viewTransition) return;
const isBack =
navigation.activationType === "traverse-backward";
document.documentElement.classList.toggle("is-back", isBack);
});
/* 后退时用更快、更收敛的动画,与"深入详情"形成方向感差异 */
.is-back::view-transition-group(hero-photo) {
animation-duration: 0.2s;
}
跨文档过渡的边界条件要清楚,满足不了时浏览器会静默回退为普通导航:
跨文档过渡生效条件:
① 仅限同源导航(跨域直接不启用)。
② 导航链路上不能有跨源重定向。
③ 新旧文档都必须用 @view-transition 选择启用。
④ 地址栏直接输入 URL 这类非页面内触发的导航不包含在内。
七、在 React 等框架中使用:小心异步状态更新
React 集成的坑在于:startViewTransition 的回调期望 DOM 在回调返回时就完成更新,而 React 的状态更新默认是批量异步调度的。如果直接在回调里 setState,浏览器截到的新快照可能还是旧 DOM。解决工具是 flushSync:
import { flushSync } from "react-dom";
import { useState } from "react";
/**
* React 中的同文档过渡
* 用 flushSync 强制状态更新同步刷新到 DOM,再让浏览器截图
*/
export function ViewSwitcher() {
const [showDetail, setShowDetail] = useState(false);
/** 切换到详情 */
const goDetail = () => {
document.startViewTransition(() => {
flushSync(() => setShowDetail(true));
});
};
/** 返回列表 */
const goBack = () => {
document.startViewTransition(() => {
flushSync(() => setShowDetail(false));
});
};
return showDetail ? <Detail onBack={goBack} /> : <List onOpen={goDetail} />;
}
使用 Suspense、流式数据或路由库时,如果新视图的数据未就绪,可以先在过渡期间显示占位,数据到达后再做第二次过渡,避免截到半成品页面。各大元框架也在把这套机制封装进自己的路由导航 API,接入前先查当前版本的官方文档,避免与框架内建过渡重复触发。
Vue 同理:把 DOM 变更放进 startViewTransition 回调,并确保 DOM 已更新(可在 nextTick 之后让快照捕获,或等待框架提供的过渡钩子)。核心原则跨框架一致:先保证新 DOM 真实存在,再交还控制权给浏览器。
八、无障碍:尊重"减少动态效果"的系统设置
过渡动画会引发部分用户的前庭不适,必须响应用户的系统级偏好设置 prefers-reduced-motion。最省心的做法是在用户偏好减少动画时关闭自定义动画(浏览器会退化为即时切换,功能完全不受影响):
/* 用户在系统中开启"减少动态效果"时,不施加自定义动画 */
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
也可以在 JS 层直接跳过过渡、只做状态更新:
/**
* 根据系统偏好决定是否用过渡包裹 DOM 更新
* 偏好减少动画时直接更新,不创建过渡
*/
function updateView(updateDom) {
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (reduceMotion || !document.startViewTransition) {
updateDom();
return;
}
document.startViewTransition(updateDom);
}
九、降级:不支持时,体验退化为"正常跳转"
View Transitions 的降级极其优雅:**它本质上只是一层视觉增强,去掉它,DOM 更新与页面跳转照常工作。**因此特性检测就足够了:
/**
* 安全调用同文档过渡
* 旧浏览器直接执行更新,行为与加动画前完全一致
*/
function safeTransition(updateDom) {
if (typeof document.startViewTransition === "function") {
document.startViewTransition(updateDom);
} else {
updateDom();
}
}
跨文档模式无需写 JS 降级:不支持的浏览器会忽略 @view-transition 规则,页面按最普通的方式跳转。view-transition-name 这个 CSS 属性在旧浏览器里也只是被忽略,不影响布局。
降级策略总结:
- 同文档:特性检测 document.startViewTransition,有则增强、无则直改。
- 跨文档:CSS 渐进增强,不支持即普通导航,零副作用。
- 永远不要把核心功能(路由、数据)依赖在过渡是否执行上。
十、性能与使用边界
View Transitions 的动画跑在合成线程上,正常使用比 JS 驱动的属性动画更省主线程,但仍有边界:
性能注意事项:
① 快照有成本:超大区域、复杂滤镜、超大图片的快照会增加开销,
给过渡元素合理命名、避免整页巨量内容同时动画。
② 动画只用合成属性思路:浏览器内部已优化位置/尺寸补间,
自定义时优先 opacity/transform,避免在关键帧里触发
layout 的属性。
③ 别在过渡期间做重活:startViewTransition 回调里只更新 DOM,
数据请求、复杂计算应在过渡外完成。
④ 列表唯一命名:动态命名 + 及时清理,养成习惯,
重名是最常见的"动画莫名失效"原因。
适合使用的场景:列表↔详情、标签页切换、设置项展开、图片灯箱、主题切换、播放器迷你条↔全屏。不适合滥用的场景:高频连续交互(拖拽跟手、输入联想)、需要逐帧精确控制的复杂编排——那些仍应交给专门的动画方案。
十一、落地清单
上手阶段
□ 用 startViewTransition 包一个标签切换,体验默认淡入淡出
□ 给一对共享元素设置相同 view-transition-name,观察自动补间
□ 加 prefers-reduced-motion 与特性检测降级
列表/详情阶段
□ 点击时动态命名被点击卡片,保证同名全局唯一
□ 自定义 group/old/new 的时长、缓动与交叉淡化
□ React 中用 flushSync 保证快照捕获新 DOM
MPA 阶段
□ 新旧文档都加 @view-transition { navigation: auto }
□ 用 pageswap/pagereveal 区分前进/后退动画
□ 核对同源、无跨源重定向等生效前提
结语:动画的归宿是成为浏览器的基础设施
前端动画的发展脉络,是一条"把高频通用的东西从业务代码下沉到平台"的历史:布局交给 CSS、手势交给 Pointer Events、字体加载交给 Font Loading API。共享元素过渡曾经是衡量一个前端"会不会做动画"的高难度动作,如今它也走完了这条路——开发者只需要声明"这两个元素是同一个东西",剩下的测量、配对、补间全部由浏览器完成。
当动画的边际成本趋近于零,真正稀缺的就变成了判断力:**哪里值得动、动多快、如何不打扰用户、如何尊重不想要动画的人。**工具会越来越强,而克制与同理心,始终是体验设计师无法外包给浏览器的那部分工作。
�� 同主题文章
前端状态管理完整实战 2026:从 Redux 到 Signals 再到 Server State
前端状态管理是 React 生态永恒的话题。从 Class 时代的 Redux 到 Hooks 时代的 Context + useReducer,再到 2024 年 Signals 的兴起和 2025 年 Server State 的深度整合,状态管理的范式在持续演进。核心矛盾从未改变:状态在哪里放、怎么同步、组件怎么订阅。本文完整实战 2026 年前端状态管理:状态分类(UI / 服务端 / 全局)、Redux 到 Zustand 的简化路线、Signals 细粒度响应式的原理与迁移、Server State 与本地状态的边界、缓存策略与乐观更新、以及独立开发者的选型决策树。
Web 性能优化完整实战 2026:INP 时代的 Core Web Vitals 与渲染性能
2024 年 INP 取代 FID 成为 Core Web Vitals 的正式指标后,前端性能优化的重心从「加载快不快」转向「用起来顺不顺」。LCP 管首屏、INP 管交互、CLS 管稳定,三个指标共同决定用户对网站的真实体感,也直接影响搜索排名与转化率。本文完整实战 2026 年的 Web 性能优化:三大指标的测量与阈值、LCP 优化链路、INP 的三阶段拆解与优化、CLS 稳定性治理、长任务与主线程释放、资源加载策略、真实用户监控 RUM,以及独立开发者投入产出比最高的优化清单。
React Server Components 完整实战 2026:服务端渲染、流式与数据获取的架构重组
React Server Components(RSC)是 React 诞生以来最深刻的架构变革:组件被分为「服务端组件」与「客户端组件」两种,前者只在服务端运行、不占用浏览器 JavaScript 体积、可直接访问数据库,后者保留交互能力。它不是 SSR 的升级版,而是对 React 渲染模型的重新设计。本文完整实战 RSC:服务端组件与客户端组件的分工、数据获取的革命、流式渲染与 Suspense、缓存策略、与客户端状态管理的边界、迁移路径与常见误区。