登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  前端

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

来源:17golang原创

时间:2026-11-05 03:39:07 494浏览 收藏

热门推荐
漫画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删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>