web过渡动画

本文作者系360奇舞团前端开发工程师

Web 动画不仅能够提升用户界面的美观度,还能增强用户的交互体验。
ff377c5df34663470fd018615d3a564c.gif
在手机app中,经常会见到这种丝滑的交互动画,用来引导用户的视线,使用户更加关注产品的重要信息。这种交互动画在安卓端被称为共享元素动画。通过观察可以发现这种动画的特点,就是在动画前后有一个或者多个相同的元素。
那么在浏览器里前端如何实现这样的动画呢?
通常都会在触发动画的时候新建一个dom结构,计算动画元素的初始状态和最终状态,通过js的animate执行动画。也就是FLIP的思想来实现。这种实现的存在的问题是需要关注有哪些元素参与了动画,动画前后有哪些属性发生了变化,手动计算并应用到元素上。其次还需要保证元素是始终存在页面中,并且还不能实现跨页面的动画过渡。

View Transition

view transition是w3c工作组提出的一个草案,view transition允许你在可视 DOM 改变的两种状态之间添加动画过渡。这些改变的范围可以从向 DOM 添加新元素这样的小更改,到从一个页面导航到另一个页面这样的的大更改。view transition提供了一种简单的方式来实现dom的更改和动画。
目前的浏览器兼容性如下图:
5668c6b48fe170fb99fd72009599ff47.png
使用view transition可以非常简单的实现共享元素动画,那么接下来看一下view transition的相关内容吧!

View Transition的核心概念

view transition提供了一个js方法:

document.startViewTransition(updateCallback);

通过这个方法可以开启view transition。其中startViewTransition方法接收一个回调函数作为参数,在回调函数updateCallback 里,我们执行变更 DOM 状态的逻辑,比如切换页面路由、更新页面内容等。
下图是没有使用view transiton和使用了view transtion的对比:
d71fd6fd431c741e0ecdee3ab9a656e4.gif
在调用了startViewTransition后会得到一个只读的promise对象,这个对象有三个属性,代表了过渡动画中的三个状态节点:
1.  updateCallbackDone: 回调函数执行完毕。
2.  ready:准备完毕即将准备播放动效。
3.  finished:动效执行结束。
这三个属性也都是promise对象,可以使开发者更精准的控制动画的过程。

const withTransitionButton = document.querySelector('.with-transition button');

    withTransitionButton.addEventListener("click", async (e) => {
      
      const vt = document.startViewTransition(() => { 
        const newImage = document.createElement("img");
        newImage.src = "//p5.img.360kuai.com/t01ab608eed52439d4a.jpg";   
        e.target.parentElement.appendChild(newImage);   

        console.log('Update Callback')
      });  
      console.log('View Transition Instance', vt);

      // vt.skipTransition();

      // updateCallback函数执行状态 会在 updateCallback函数执行完时兑现
      await vt.updateCallbackDone;
      console.time('Callback Done');

      // 跳过快照动画,但不会跳过updateCallback函数执行
      vt.skipTransition();

      // 动画是否准备好 会在伪元素树被创建且过渡动画即将开始时兑现
      await vt.ready
      // console.log('Transition Ready');

      // vt.skipTransition();

      // 转场动画是否执行完 会在转场过渡动画完成时兑现
      await vt.finished
      console.log('Transition Finished');
      
    });

返回的promise对象还有一个skipTransition方法,可以跳过动画效果而不影响updatecallback函数的执行。

View Transition背后的运行机制

view transition的API设计非常简单,那么浏览器是如何实现这种过渡动画的呢?
当调用document.startViewTransition方法的时候,浏览器会捕获当前的页面状态作为旧视图,暂停浏览器的渲染,执行updatecallback函数,更新dom,这个时候虽然dom更新了,但是并没有渲染,所以用户看的内容并没有变化。浏览器会再次捕获到当前dom的状态作为新视图。updatecallback执行完后,updateCallbackDone的状态变更。
411df235762c9e9634017cf748e9e01c.png
浏览器会利用刚刚生成的新旧视图,创建一系列伪元素,插入到 html 节点中。旧、新视图,对应着上文提到的两个伪元素:::view-transition-old、::view-transition-new。
f4e3ff48f019825976927bdcff0b2b3c.png
之后再恢复渲染,这时用户会看到伪元素渲染的样式,此时的ready状态完成。
浏览器会对这些伪元素执行动画。伪元素的层级是最高的,所以在执行动画的过程中,页面不能进行任何的交互。
动画结束后,添加到页面的伪元素会被浏览器移除。finished状态完成。
(在 W3C 标准文档中,有一个步进式 Demo,可以帮我们更直观地了解生命周期的每个阶段)。

View Transition的视图命明和自定义动画

在核心概念里的demo可以看到view transition的动画是交叉淡化动画,这个是view transition的默认动画。在运行机制里我们了解到view transition是通过伪元素来实现动画的,所以也就支持通过css来自定义动画。
以下面的元素点击后变小删除的demo来看一下view transition如何自定义动画。
835876dcc9b6bf9c86a01210b3ccec06.gif

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    #box{
      width: 100px;
      height: 100px;
      background: red;
      view-transition-name: box;
      border-radius: 50%;
    }

    @keyframes scale-small {
      from {
        transform: scale(1);
      }
      to {
        transform: scale(0);
      }
    }
    ::view-transition-old(box) {
      animation: scale-small 2s forwards;
    }
  </style>
</head>
<body>
  <div id="box"></div>
  <script>
    document.getElementById('box').addEventListener('click', (e) => {
      document.startViewTransition(() => {
        e.target.remove()
      })
    })
  </script>
</body>
</html>

为了保证动画只作用到删除元素,需要给元素定一个view-transition-name的css属性来命名视图转换。之后就可以用::view-transition-old(box)选择到这个元素的旧状态,并对其设置动画。
当一个页面中有多个命名视图的话,就会产生多组的伪元素结构:
0029cca0a7caa39e49cf9e47847a80a2.png
其中视图转换不要求在同一个元素上,可以是不同的元素,但要保证在一个页面中是唯一的。

View Transition的多页面

到目前为止,过渡效果只能在同一文档中实现,但是view transition它允许你在跨不同文档导航时添加过渡。换句话说,你还可以向多页面应用程序添加过渡效果。
要启用这些页面之间的视图转换,你需要做的就是将以下  标记添加到文档的 HTML  中:

<meta name="view-transition" content="same-origin">

可以通过这个demo(https://view-transition-demo-crossfade.netlify.app/)来查看效果(在使用chrome的时候需要浏览器版本>111 并且手动启用了view transition的api)

开源框架对View Transition的支持
  1. Astro v2.9 (https://astro.build/blog/astro-290/)

  2. SvelteKit 从1.24 版本,集成了View Transition API (https://svelte.dev/blog/    view-transitions)

  3. Nuxt.js v3.4 将view transition作为实验性功能引入 (https://nuxt.com/blog/v3-4#view-transitions-api-support)

  4. React-router v6.17.0 (https://github.com/remix-run/react-router/blob/main/ CHANGELOG.md#view-transitions-)

总结

创建平滑的页面过渡一直是 Web 开发的目标。View Transitions API 是实现这一目标的一大进步。它允许开发人员在网站上添加有吸引力的动画。

- END -

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

d557070684643f12e5906d671bec1f1f.png

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值