当前位置:首页 > 文章列表 > 文章 > 前端 > CSS view transitions怎样为同文档状态切换设置过渡

CSS view transitions怎样为同文档状态切换设置过渡

来源:17golang原创 2026-11-05 03:39:07 0浏览 收藏
热门推荐
漫画APP
动画内容聚合,热门资源快捷查看
立即下载

如果单页应用只是把列表替换成详情,传统做法通常是给容器加一个淡入动画,再手动处理旧内容的离场。CSS View Transitions 把这件事拆成了更清晰的两层:JavaScript 负责在同一个文档中提交状态变化,CSS 负责给变化前后的快照定义动画。

本文只讨论同文档状态切换,例如筛选列表、切换卡片详情或更新局部面板。官方资料入口:

官方地址:https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition

最小用法是把真正修改 DOM 的函数交给 document.startViewTransition()。浏览器不支持该 API 时,直接执行同一个更新函数;需要独立移动的元素再设置唯一的 view-transition-name。

先分清同文档和跨文档

同文档过渡发生在一个页面内部,通常由 SPA 的筛选、路由状态或组件更新触发。它的入口是 document.startViewTransition(updateCallback)。跨文档导航则是两个页面之间的导航,需要参与页面通过 @view-transition 选择加入;这不是本文的触发方式。

因此,本文的最小模型只有三块:旧状态快照、更新回调、新状态快照。浏览器在回调前记录旧状态,在回调完成后记录新状态,再让 CSS 过渡伪元素负责呈现变化。

同文档 View Transition 中旧状态快照、DOM 更新回调和新状态快照的关系说明图
图1:同文档 View Transition 的状态关系说明图,展示快照与 DOM 更新的边界,不是运行截图。

把原来的 DOM 更新包起来

先保留一个普通的更新函数,再让按钮点击只负责选择是否通过过渡调用它。这样写的好处是降级路径和增强路径使用同一份业务逻辑,不会因为浏览器不支持新 API 而维护两套状态代码。

const panel = document.querySelector('#panel');
const toggle = document.querySelector('#toggle');

function updatePanel() {
  // 这里只修改状态对应的 DOM,不在函数里重复创建过渡。
  panel.classList.toggle('is-expanded');
  panel.querySelector('.label').textContent = panel.classList.contains('is-expanded')
    ? '展开'
    : '收起';
}

toggle.addEventListener('click', () => {
  if (!document.startViewTransition) {
    // 不支持 API 时照常更新,功能不能依赖动画存在。
    updatePanel();
    return;
  }

  // 浏览器先保存旧状态,再执行回调并生成新状态快照。
  document.startViewTransition(() => updatePanel());
});

这个调用不要求你自己复制旧节点,也不需要先写一套离场节点。默认情况下,页面根快照会使用淡入淡出和尺寸变化完成基本过渡;如果只需要一个轻量状态切换,到这里就足够了。

用唯一名称把元素从 root 中拆出来

当卡片、标题或封面需要独立移动时,给它一个 view-transition-name。名称对应参与过渡的快照,必须保证同一时刻的渲染元素不重复使用同一个名称;否则过渡可能被跳过。

.product-card.is-active {
  /* 这个元素会从 root 快照中拆出独立的图像对。 */
  view-transition-name: active-card;
}

::view-transition-group(active-card) {
  /* 组控制新旧快照的几何变化时间。 */
  animation-duration: 260ms;
}

::view-transition-old(active-card) {
  /* 旧卡片离场时略微缩小,避免和新状态硬切。 */
  animation: card-out 160ms ease both;
}

::view-transition-new(active-card) {
  /* 新卡片从轻微缩小和透明状态进入。 */
  animation: card-in 220ms ease both;
}

@keyframes card-out {
  to { opacity: 0; transform: scale(.96); }
}

@keyframes card-in {
  from { opacity: 0; transform: scale(.96); }
}

如果列表中有多个需要独立处理的项目,不要把同一个固定名称同时写给所有元素。可以在状态更新时只给当前元素命名,也可以在适用的同文档场景使用 match-element 让浏览器分配内部唯一名称,但不要把它当成跨文档名称传递方案。

view-transition-name 将一个卡片从 root 快照中拆成独立命名快照的关系说明图
图2:view-transition-name 的快照分层说明图,展示 root、独立元素和唯一命名约束,不是运行截图。

过渡伪元素负责最后的节奏

同文档过渡会暴露一组 CSS 伪元素。::view-transition-old(root) 和 ::view-transition-new(root) 控制根快照,带名称的元素则使用对应名称作为参数。可以先改持续时间和透明度,再决定是否需要更复杂的位移。

::view-transition-old(root),
::view-transition-new(root) {
  /* 根状态切换保持短而稳定,避免遮住用户操作反馈。 */
  animation-duration: 180ms;
}

::view-transition-new(active-card) {
  /* 用自定义关键帧替换默认淡入,名称必须和元素保持一致。 */
  animation-name: card-in;
}

@media (prefers-reduced-motion: reduce) {
  /* 用户要求减少动效时,缩短为几乎不可感知的过渡。 */
  ::view-transition-group(*) {
    animation-duration: 1ms;
  }
}

不要把动画结果当成状态同步机制。数据和可访问性状态仍应在更新回调里完成,CSS 只负责呈现从旧快照到新快照的视觉过程。

不生效时先看三个边界

现象优先检查处理方式
点击后没有过渡document.startViewTransition 是否存在保留直接执行更新函数的降级分支,不把动画当成业务前提
命名元素动画被跳过同一时刻是否有多个渲染元素使用相同名称确保名称唯一,或改用适合当前同文档列表的自动匹配方式
改了 CSS 但仍是默认淡入伪元素参数是否与名称一致检查 ::view-transition-old(name) 和 ::view-transition-new(name) 的 name

最后再确认更新回调确实改变了 DOM。没有状态差异时,浏览器没有可动画的新旧内容;而在用户偏好减少动效时,应该优先保证信息更新和焦点顺序,再把动画压缩到极短。

采用前的最小清单

  • 只在同一个文档内更新 DOM 时使用 document.startViewTransition()。
  • 把业务更新集中到回调函数,并准备不支持 API 的直接更新路径。
  • 给独立动画元素设置唯一的 view-transition-name。
  • 先调伪元素的持续时间,再逐步添加位移和缩放,避免过渡遮挡操作反馈。
  • 尊重 prefers-reduced-motion,不要让动画成为信息传递的唯一方式。

相关问题

同文档过渡必须使用单页应用吗?

不一定,关键是状态更新发生在同一个文档里,并且能够在回调中修改 DOM。SPA 是常见场景,但普通页面中的局部交互也可以采用相同思路。

为什么 view-transition-name 不能随便重复?

名称用于区分独立快照。多个渲染元素同时拥有同名标识时,浏览器无法建立一一对应关系,过渡可能被跳过。

@view-transition 能替代 startViewTransition 吗?

不能把两者混为一谈。本文的同文档状态切换由 JavaScript 调用 startViewTransition;@view-transition 主要用于跨文档导航的加入声明。

把 DOM 更新和视觉过渡分开之后,最小实现其实只有一个回调和一组伪元素。先确保不支持新 API 时功能仍然正常,再按元素的实际阅读关系添加唯一名称,通常比一开始复制整套动画状态更容易维护。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
CSS timeline-scope怎样让不同滚动容器共享命名时间线CSS timeline-scope怎样让不同滚动容器共享命名时间线
上一篇
CSS timeline-scope怎样让不同滚动容器共享命名时间线
JavaScript Iterator.from怎样把类迭代对象统一转换
下一篇
JavaScript Iterator.from怎样把类迭代对象统一转换
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    888次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    888次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    971次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    957次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    782次使用