让我们来写一个卡片弹出动画

5,399 阅读5分钟

准备工作

挖槽 好牛逼

为了能更容易理解,在开始之前,我们要先达成4个共识。

4个共识

唱 跳 rap 打篮球

... 咳咳咳 不好意思,跑题了

下面 真的开始了 :

1. transition 和 animation

让我们回忆下是怎么用使用动画的:

(1)transition

.foo { width: 100px; trantions:  1s; }

.foo:hover { width: 120px;}

设置元素 两个不同的状态 和 过渡的时间。

当我们触发变化,浏览器看到样式变化之后,为我们创建动画

(2)animation

@keyframes cardaniIn {
   0%,
   39%,
   100% {
    -webkit-animation-timing-function: cubic-bezier(1, 0, 0.47, 1);
    animation-timing-function: cubic-bezier(1, 0, 0.47, 1);
   }
   
   0% {
    -webkit-transform: rotateY(0deg) scale(0.8) translate3d(0, 0, 0);
    transform: rotateY(0deg) scale(0.8) translate3d(0, 0, 0);
  }
  
  39% {
    -webkit-transform: rotateY(0deg) scale(0.8) translate3d(0, -50px, 0);
    transform: rotateY(0deg) scale(0.8) translate3d(0, -50px, 0);
   }
   
   100% {
    -webkit-transform: rotateY(180deg) scale(1) translate3d(0, 0, 0);
    transform: rotateY(180deg) scale(1) translate3d(0, 0, 0);
   }
 }

animation

animation 允许我们写多个状态值,为我们解锁了一次告诉浏览器多个状态变化的能力。

共同点就是,

告诉浏览器我们想要的样式,并让浏览器看到样式的变化

浏览器看东西的方式和我们不太一样,

浏览器一秒有很多帧,每一帧浏览器都会做很多事情,

其中包括计算style的变化,

2个帧之间

因为我们的修改 导致 元素的样式不一样的时候,浏览器就看到了样式的变化,并创建动画。

我们要达成的第 1 个共识就是:

我们创建动画,实际是在告诉浏览器 不同帧之间 元素样式的变化。

2. 动画尽量只用 transform 和 opacity

浏览器1s有很多帧,每一帧浏览器都会做大量的工作。

其中 layout 重新布局 paint 绘制 是最耗时的两个工作。

transformopacity 的只会触发 composite合成的这一个步骤,

了解这一点 是我们创建流畅动画的关键

我们要达成的第 2 个共识就是:

动画尽量只用 transform 和 opacity

3. display 和 visibility

display:none;visibility: hidden;都会让元素不可见,

(1)display:none; 不可见,不占据空间,更彻底,会把元素从render tree移走,发生一次重排。

(2)visibility: hidden;让元素视觉上不可见,并且不可点击交互。但是仍然占据空间,可以获得位置等相关信息,切换visibility不会发生重排。

所以在特定的情况下,比如我们将要写的动画中(下面会说,需要元素不可见,但是需要位置信息),可以用visibility: hidden;来隐藏元素。

我们要达成的第 3 个共识就是:

可以考虑用visibility控制元素的显隐

6. 996 的压力会让人数学和记忆能力变差

秃然

FLIP

让我们开始吧

我们把动画分成2个部分,第一个部分,整体的位置和大小变化

整体变化

还记得我们的第 1 条共识吗,

我们创建动画,实际是在告诉浏览器 不同帧之间 元素样式的变化。

现在一样,这个动画包括宽高和位置变化,我们需要告诉浏览器2个帧的 width offsetTop offsetLeft

2个帧

FISRT

获取第一帧的样式

var fisrtDom = params.fisrtDom;
var fisrtReact = fisrtDom.getBoundingClientRect();
console.log( fisrtReact )

第一帧

LAST

获取最后一帧的样式

var lastDom = params.lastDom;
var lastReact = lastDom.getBoundingClientRect();
console.log( lastReact );

Invert

现在让我们计算两个状态的差值,并把差值应用在要动画的元素上。

还记得我们的第 2 和 第 3 条共识吗,

动画用 transform ,元素的显隐用visibility

所以这里我们用的是 transform 和 元素的显隐用visibility。

play

最后,让它动起来吧。

当我们 取消 transform 的值的时候,元素的transform将会变回 默认的 translate3d(0,0,0) scalce(1),

浏览器看到样式的变化 和 transtion 就会为我们创建动画了。

实际上,这是一种叫做 FLIP 的技术。

first (第一帧) L (最后一帧) I (倒转) P (播放)

专门用于创建这种动画

第二部分动画比较简单,留给大家自由发挥。

web Animations Api

有一个叫做 web Animations Api 的api, 对我们创建动画有很大的帮助,

让我们能用编程的方式创建动画。

像我们的例子中,可以这样用

web Animations Api 最棒的地方在于, 能把动画实例保存起来,

我们在做卡片收起动画的时候,不用再次计算。

直接 animateInstance.reverse() 就可以反转播放动画。

web Animations Api 不是本文的重点,可以自行去了解一下 它 和 它的 poyFill 低版本兼容的插件。


参考资料

性能优化 developers.google.cn/web/fundame…

CSS动画你应该知道的10件事 www.yuque.com/cssconf/5th…

FLIP相关 www.w3cplus.com/animation/h…

FLIP相关 www.w3cplus.com/javascript/…


... ...

动画虽然完成了,但是由于 个人能力 和 项目的进度,

已经不允许我,去解决路由和分享页面的问题了,很遗憾,没上到正式环境

心塞,为了不拖项目进度,每天起早一个小时写这个东西,还是流产了。以后闲下来可以会再捡起来

... ...

这不是一篇严谨的教程,更多的是我个人的总结和分享,

文中可能会有错误遗漏的地方,请多多见谅,权当抛砖引玉。

加 coco 的qq群 418766876,一起交流鸭...

. . . 苹果的动画好细腻精致 . . .