效果示例
视频来源于 GitHub,存在无法播放的情况
原理浅析
跨页面共享元素动画实现的方法其实并非真的操作 DOM 移动,而是先把需要移动的页面或者元素存为图片,然后再通过对图片添加动画实现跨页面“共享元素”动画。未来还会更新加强版:computed style + 图片,可以更精细地控制 CSS 样式而不是只操作一张图片。也正因为动的是截图,整个画面在过渡时不会响应任何点击事件,一定程度上减少了极限操作造成的 bug。
值得注意的是,基于跨页面过渡的原理,我们可以推测,在动画执行的时候,目标页面其实已经渲染好了(才会有目标图片),所以使用跨页面过渡动画有一个缺点,那就是有一定延迟。
可以想象过渡过程中,在画面顶层会有这么一组元素覆盖着原本的元素,所以你无法点击原来画面上的元素。默认情况下 outgoing-image
和 incoming-image
的过渡是一个淡入淡出动画,我们可以通过下面这些 CSS 选择器控制这两个图片的动画:
例如把动画延长到 5 秒:
再例如把淡入淡出改为其他动画:
多元素参与过渡
上面的代码仅仅是对整个页面(root)添加过渡动画,然而更常见的需求肯定是对某个元素的过渡。为此我们需要把某个元素指定为过渡使用元素:
P.S. break-inside: avoid;
和 contain: paint;
是实现跨页过渡的重要属性
设置后,过渡用的“图片”结构会像这样:
对过渡动画的操作与 root 别无二致,仅仅是把 root 换成对应的 tag 就可以了:::page-transition-outgoing-image(site-header)
调用过渡 API
仅配置 CSS 无法实现过渡,还需要调用 document.createDocumentTransition
告诉浏览器执行过渡操作:
这个过程步骤如下:
- 在
start
的 callback 运行时,浏览器已经获取当前截图,并且整个页面被截图覆盖,所以从用户角度看,整个画面都是静止无响应的
- 在 callback 中对 DOM 进行操作,因为当前画面仍是截图,所以即使 DOM 操作完成,用户也依然看到旧画面
- callback 运行结束后,拿到新的页面截图,过渡才正式开始
await start
后,过渡动画完成,移除过渡用的截图,新页面可操作
还可以通过修改 el.style.pageTransitionTag
临时调整过渡方式:
多页面过渡
上述操作仅限单页面应用,虽然这个 API 的目标是使多页面应用也能进行共享元素过渡,但是浏览器暂时未支持,只能通过代码来预习一下,基本概念不变,跨页面的重点是在页面隐藏和新页面展示前对元素进行操作:
来试试
初步了解跨页面过渡接口和 CSS 配置后,应该可以理解这个简单的例子啦!大家赶紧打开 chrome://flags/#document-transition
,试试通过修改这个例子更深入理解共享元素动画吧!
https://codepen.io/ssshooter/pen/GRxjGXJ