如何实现css页面切换的平滑遮罩过渡_利用css-view-transitions-api

View Transitions API 不是 CSS 动画替代品,而是导航级过渡机制

它不靠 transition 或 @keyframes 实现遮罩效果,而是由浏览器在页面导航(如 history.pushState、router.push)时自动捕获 DOM 变化,并对「旧元素」和「新元素」分别生成快照,再用合成层做过渡。遮罩感需手动叠加伪元素或 backdrop —— 它本身不提供遮罩层。

必须显式开启 View Transition 并包裹更新逻辑

直接写 document.startViewTransition(() => { location.href = ‘/next’ }) 会失败:现代框架(如 Vue Router、React Router v6.22+)默认禁用原生 View Transitions;纯 HTML 导航也不触发。正确做法是:

确保启用条件:Chrome 111+、Edge 111+,且页面无 document.domain 修改用 document.startViewTransition() 包裹 DOM 更新动作,不是导航动作本身在单页应用中,应在路由守卫或组件挂载后调用,例如 Vue 中:onMounted(() => { document.startViewTransition(() => { // 触发数据更新或 class 切换,让视图重渲染 isActive.value = true })})

遮罩效果要靠 ::view-transition-old() 和 ::view-transition-new() 配合 backdrop-filter 或伪元素

想实现「淡入遮罩」,不能只动 opacity:浏览器会把旧/新内容作为独立合成层处理,需主动控制它们的堆叠与视觉样式。常见组合:

给旧内容加半透明黑色背景:::view-transition-old(root) { background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(2px);}用 ::view-transition-group 控制整体缩放/位移,避免遮罩“撕裂”:::view-transition-group { clip-path: inset(0); transform: scale(0.98);}禁止默认 fade 效果干扰遮罩:显式重置 opacity,否则旧元素可能提前消失:::view-transition-old(root), ::view-transition-new(root) { opacity: 1 !important;}

服务端渲染(SSR)和静态站点要注意生命周期时机

在 DOMContentLoaded 之前调用 startViewTransition 会报错 InvalidStateError: No active navigation;而 SSR 页面首次加载时没有「导航上下文」,View Transitions 不生效。实际方案:

立即学习“前端免费学习笔记(深入)”;

仅在客户端路由跳转时启用,服务端首屏不触发过渡监听 navigation 事件而非点击事件:navigation.addEventListener(‘navigate’, (e) => { e.intercept(async (interception) => { document.startViewTransition(() => interception.commit()); });});若用 Astro / SvelteKit,需在 onMount 中检查 document.activeElement 是否为 body,避免 hydration 冲突

遮罩过渡真正难的不是写几行 CSS,而是理解 View Transitions 的触发边界 —— 它只在「一次导航 + 一次 DOM 更新」的原子操作中有效,跨框架状态同步、异步数据加载、CSS-in-JS 注入顺序,都可能让它静默失效。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。