首頁  >  文章  >  web前端  >  詳解CSS和JS動畫底層原理及如何優化它們的性能

詳解CSS和JS動畫底層原理及如何優化它們的性能

coldplay.xixi
coldplay.xixi轉載
2020-12-10 17:37:083458瀏覽

javascript欄位介紹CSS和JS動畫底層原則

詳解CSS和JS動畫底層原理及如何優化它們的性能

相關免費學習推薦:javascript#(影片)

##概述

你肯定知道,動畫在創建引人注目的Web 應用程式中扮演著重要的角色。隨著使用者越來越多地將注意力轉移到使用者體驗上,商家開始意識到完美、愉快的使用者體驗的重要性,結果 Web 應用程式變得越來越重,並具有​​更動態互動的 UI。這一切都需要更複雜的動畫,以便用戶在整個過程中更平穩地進行狀態轉換。今天,這甚至不被認為是什麼特別的事。用戶正變得越來越挑剔,預設情況下,他們期望的是具有高響應性和互動性的用戶介面。

然而,介面的動畫化並不一定是簡單的。什麼是動畫,什麼時候該用動畫,動畫應該有什麼樣的影片效果,這些都是棘手的問題。

JavaScript 和 CSS 動畫比較

建立 Web 動畫的兩個主要方法是使用JavaScript和 CSS。選擇哪一種沒有對或錯,這完全取決於你想要達到的效果。

CSS 動畫

用CSS製作動畫是讓元素在螢幕上移動的最簡單方法。

這裡將從如何讓元素在 X 和 Y 軸上移動 50px 簡單範例開始,透過持續 1 秒的 CSS 過渡來移動元素。

.box {
  -webkit-transform: translate(0, 0);
  -webkit-transition: -webkit-transform 1000ms;

  transform: translate(0, 0);
  transition: transform 1000ms;
}

.box.move {
  -webkit-transform: translate(50px, 50px);
  transform: translate(50px, 50px);
}
當元素加上

move 類別時,改變 transform 的值然後開發發生過渡效果。

除了轉換持續時間外,還有

easing 屬性,這實際上就是動畫的運動速度方式,該參數會在之後詳細介紹。

如果像上面的程式碼片段一樣,創建單獨的 CSS 類別來實現動畫,當然也可以使用 JavaScript 來切換每個動畫。

如下元素:

p class="box">
  Sample content.
然後,使用 JavaScript 來切換每個動畫。

var boxElements = document.getElementsByClassName('box'),
    boxElementsLength = boxElements.length,
    i;

for (i = 0; i 上面的程式碼片段是為所有包含 <p>box<code> 類別的元素為其添加 </code>move<code> 類別以觸發動畫。 </code></p>這樣做可以為你的應用提供良好的平衡。你可以專注於使用 JavaScript 管理狀態,只需在目標元素上設定適當的類,讓瀏覽器處理動畫。如果沿著這條路線前進,你可以在元素上監聽<p>transitionend<code> 事件,但前提是放棄舊版Internet Explorer 的支援:</code></p><p><img src="https://img.php.cn/upload/image/590/600/983/1607592778931586.png" title="1607592778931586.png" alt="詳解CSS和JS動畫底層原理及如何優化它們的性能">##監聽</p>transitionend<p> 觸發的事件如下所示:<code><pre class="brush:php;toolbar:false">var boxElement = document.querySelector('.box');
boxElement.addEventListener('transitionend', onTransitionEnd, false);

function onTransitionEnd() {
  // Handle the transition finishing.
}
除了使用CSS 過渡之外,你還可以使用CSS 動畫,CSS 動畫可以讓你更好地控制單獨的動畫關鍵幀,持續時間以及循環次數。

關鍵影格用於指示瀏覽器 CSS 屬性在給定時間點上應有的 CSS 屬性,然後填入空白。

來個簡單的例子:

.box {
  /* 动画的名字 */
  animation-name: movingBox;

  /* 动画的持续时间 */
  animation-duration: 2300ms;

  /* 动画的运行次数 */
  animation-iteration-count: infinite;

  /* 设置对象动画在循环中是否反向运动的方法 */
  animation-direction: alternate;
}

@keyframes movingBox {
  0% {
    transform: translate(0, 0);
    opacity: 0.4;
  }

  25% {
    opacity: 0.9;
  }

  50% {
    transform: translate(150px, 200px);
    opacity: 0.2;
  }

  100% {
    transform: translate(40px, 30px);
    opacity: 0.8;
  }
}

效果範例: https://sessionstack.github.i...

使用CSS動畫,你可以獨立於目標元素定義動畫本身,並使用animation-name 屬性選擇所需的動畫。

CSS 動畫在某種程度仍然需要加瀏覽器前綴的,在 Safari、Safari Mobile 和 Android 中都使用了 -webkit。 Chrome、 Opera、Internet Explorer 和 Firefox 都不需要添加前綴。許多工具可以幫助你建立所需 CSS 的前綴,這樣就不需要在原始檔中帶樣式前綴。

JavaScript 動畫

和 CSS 轉換或 CSS 動畫相比,使用 JavaScript 建立動畫更加複雜,但它通常為開發人員提供了更強大的功能。

JavaScript 動畫是作為程式碼的一部分內嵌編寫的。你也可以將它們封裝在其他物件中。以下為用 JavaScript 來實現最開始的 CSS 過渡的程式碼:

var boxElement = document.querySelector('.box');
var animation = boxElement.animate([
  {transform: 'translate(0)'},
  {transform: 'translate(150px, 200px)'}
])

animation.addEventListener('finish', function() {
  boxElement.style.transform = 'translate(150px, 200px)';
})

預設情況下,Web 動畫只會修改元素的展示效果。如果要將物件停留在移動後的位置,則應在動畫完成時修改其基礎樣式。這就是為什麼在上面的範例中監聽

finish

事件,並將box.style.transform 屬性設定為translate(150px, 200px),該屬性值和CSS 動畫執行的第二個樣式轉換是一樣的。 使用 JavaScript 動畫,你可以在每一步完全控制元素的樣式。這意味著你可以放慢動畫速度,暫停動畫,停止它們,翻轉它們,並根據需要操縱元素。如果你正在建立複雜的物件導向的應用程序,這尤其有用,因為你可以正確地封裝你想要的動畫行為。

Easing 定義

自然過渡效果會讓你的使用者對你的 Web 應用程式感覺更舒服,從而帶來更好的使用者體驗。

当然,没有任何东西从一个点到另一个点线性移动。 实际上,当事物在我们周围的物理世界中移动时,事物往往会加速或减速,因为我们不是在真空中,并且有不同的因素会影响这一点。 人类的大脑会期望感受这样的移动,所以当为网络应用制作动画的时候,利用此类知识会对自己会有好处。

以下是一些术语需要了解一下:

  • ease in  —  相对于匀速,开始的时候慢,之后快
  • ease out —  相对于匀速,开始时快,结束时候间慢
  • ease-in-out —   相对于匀速,开始和结束都慢)两头慢

Easing 关键字

CSS 过渡和动画允许你选择要使用的 easing 类型。 不同的关键字会影响动画的 easing,你也可以完全自定义 easing 方法。

以下为可以选择用来控制 easing 的 CSS 关键字:

  • linear
  • ease-in
  • ease-out
  • ease-in-out

让我们深入来了解一下这几个兄弟,并看它们各自展示的效果是怎么样。

Linear 动画

easing 方法的的默认为 linear,以下为 linear 过渡效果的图示:

詳解CSS和JS動畫底層原理及如何優化它們的性能

随着时间增加,值等比增加,使用 linear 动效,会让动画不自然,一般来说,避免使用 linear 动效。

以下是如何实现简单的线性动画:

transition: transform 500ms linear;

Ease-out 动画

如前所述,与线性动画相比,easing out 动画开始时快,结束时候间慢,过渡效果的图示如下:

詳解CSS和JS動畫底層原理及如何優化它們的性能

一般来说,easing out过渡效果是最适合做界面体验的,因为快速地启动会给人以快速响应的动画的感觉,而结束时让人感觉很平滑这得归功于不一致的移动速度。

有很多方法可以实现 ease-out 效果,但最简单的是 CSS 中的 ease-out 关键字:

transition: transform 500ms ease-out;

Ease-in 动画

ease-out 动画相反-开始时快,结束时候间慢,过渡效果图如下:

詳解CSS和JS動畫底層原理及如何優化它們的性能

ease-out 动画相比, ease-in 可能会让人感到不寻常,由于启动缓慢给人以反应卡顿的感觉,因此会产生一种无反应的感觉。 动画结束很快也会产生一种奇怪的感觉,因为整个动画正在加速,而现实世界中的物体在突然停止时往往会减速。

ease-outlinear 动画类似,使用 CSS 关键字来实现 ease-in 动画:

transition: transform 500ms ease-in;

Ease-in-out 动画

该动画为 ease-in 和 ease-out 的合集,过渡效果图如下:

詳解CSS和JS動畫底層原理及如何優化它們的性能

不要使用太长的动画持续时间,因为它们会让你的 UI 感觉没有响应。

ease-in-out CSS 关键字来实现 ease-in-out 动画:

transition: transform 500ms ease-in-out;

自定义 easing

你也可以定义自己的 easing 曲线,这可以更好地创建自己想要的动画效果。

实际上, ease-inlinearease 关键字映射到预定义 贝塞尔曲线 ,可以在 CSS transitions specification 和 Web Animations specification 中查找更多关于贝塞尔曲线的内容。

贝塞尔曲线 (Bézier curves)

Bézier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线。 曲线定义:起始点、终止点(也称锚点)、控制点。通过调整控制点,贝塞尔曲线的形状会发生变化。 1962年,法国数学家Pierre Bézier第一个研究了这种矢量绘制曲线的方法,并给出了详细的计算公式,因此按照这样的公式绘制出来的曲线就用他的姓氏来命名,称为贝塞尔曲线

CSS3 transition-timing-function 属性,其语法如下:

transition-timing-function: linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n);

总而言之可以用cubic-bezier(n,n,n,n)的形式来表示全部的属性值,这里就涉及到贝塞尔曲线(Bézier curve)。

让我们看看贝塞尔曲线的工作原理。 贝塞尔曲线需要四个值,或者更准确地说它需要两对数字。 每对描述立方贝塞尔曲线控制点的 XY 坐标。贝塞尔曲线的起点有一个坐标 (0, 0) ,结束坐标是 (1, 1)。 你可以设置两个对号,两个控制点的 X 值必须在 [0,1] 范围内,并且每个控制点的 Y 值可以超过 [0,1] 限制,尽管规定不清楚多少。

即使每个控制点的 XY 值稍有变化,也会得到完全不同的曲线。让我们看两张贝塞尔曲线的图,两张图相近但坐标的控制结点却不同。

詳解CSS和JS動畫底層原理及如何優化它們的性能

詳解CSS和JS動畫底層原理及如何優化它們的性能

如您所见,两张图有很大的不同, 第一个控制点矢量差为 (0.045,0.183) 矢量差,而第二控制点矢量差为 (-0.427, -0.054)

第二条曲线的样式为:

transition: transform 500ms cubic-bezier(0.465, 0.183, 0.153, 0.946);

前两个数字是第一个控制点的 XY 坐标,后两个数字是第二个控制点的 XY 坐标。

性能优化

当你在使用动画的时候,你应该维持 60 帧每秒,否则会影响用户体验。

和世界上的其他事物一样,动画也会有性能的开销。一些属性的动画性能开销相比其它属性要小。例如,为元素的 widthheight 做动画会更改其几何结构并且可能会造成页面上的其它元素移动或者大小的改变,这个过程称为布局。我们在之前的一篇文章 中更详细地讨论了布局和渲染。

通常,你应该避免动画触发布局或重绘的属性。 对于大多数现代浏览器,这意味着把动画局限于 opacitytransform 属性。

Will-change

你可以使用 will-change 知浏览器你打算更改元素的属性,这允许浏览器在进行更改之前进行最适当的优化。但是,不要过度使用 will-change,因为这样做会导致浏览器浪费资源,从而导致更多的性能问题。

will-change 用法如下:

.box {
  will-change: transform, opacity;
}

该属性在 Chrome, Firefox,Opera 得到很好的兼容。

詳解CSS和JS動畫底層原理及如何優化它們的性能

JavaScript 动画和 CSS 动画该如果抉择

  • 根据 Google Developer,渲染线程分为 主线程 (main thread)合成线程 (compositor thread)。如果 CSS 动画只是改变 transformsopacity,这时整个 CSS 动画得以在 合成线程 完成(而JS动画则会在 主线程 执行,然后触发合成线程进行下一步操作),在 JS 执行一些昂贵的任务时,主线程繁忙,CSS 动画由于使用了合成线程可以保持流畅
  • 在许多情况下,也可以由合成线程来处理 transformsopacity 属性值的更改。
  • 对于帧速表现不好的低版本浏览器,CSS3可以做到自然降级,而JS则需要撰写额外代码。
  • CSS动画有天然事件支持(TransitionEnd、AnimationEnd,但是它们都需要针对浏览器加前缀),JS则需要自己写事件。
  • 如果有任何动画触发绘画,布局或两者,则需要 “主线程” 才能完成工作。 这对于基于 CSS 和 JavaScript 的动画都是如此,布局或绘制的开销可能会使与 CSS 或 JavaScript 执行相关的任何工作相形见绌,这使得问题没有实际意义。
  • CSS3有兼容性问题,而JS大多时候没有兼容性问题。

总结

如果动画只是简单的状态切换,不需要中间过程控制,在这种情况下,css 动画是优选方案。它可以让你将动画逻辑放在样式文件里面,而不会让你的页面充斥 Javascript 库。然而如果你在设计很复杂的富客户端界面或者在开发一个有着复杂 UI 状态的 APP。那么你应该使用 js 动画,这样你的动画可以保持高效,并且你的工作流也更可控。所以,在实现一些小的交互动效的时候,就多考虑考虑 CSS 动画。对于一些复杂控制的动画,使用 javascript 比较可靠。

以上是詳解CSS和JS動畫底層原理及如何優化它們的性能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除