JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能
摘要: 理解浏览器渲染。
Fundebug经授权转载,版权归原作者所有。
这是专门探索 JavaScript 及其所构建的组件的系列文章的第 13 篇。
如果你错过了前面的章节,可以在这里找到它们:
- JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述!
- JavaScript 是如何工作的:深入V8引擎&编写优化代码的5个技巧!
- JavaScript 是如何工作的:内存管理+如何处理4个常见的内存泄漏 !
- JavaScript 是如何工作的:事件循环和异步编程的崛起+ 5种使用 async/await 更好地编码方式!
- JavaScript 是如何工作的:深入探索 websocket 和HTTP/2与SSE +如何选择正确的路径!
- JavaScript 是如何工作的:与 WebAssembly比较 及其使用场景 !
- JavaScript 是如何工作的:Web Workers的构建块+ 5个使用他们的场景!
- JavaScript 是如何工作的:Service Worker 的生命周期及使用场景!
- JavaScript 是如何工作的:Web 推送通知的机制!
- JavaScript是如何工作的:使用 MutationObserver 跟踪 DOM 的变化!
- JavaScript是如何工作的:渲染引擎和优化其性能的技巧!
- 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 来切换每个动画。
如下元素:
<div class="box">
Sample content.
</div>
然后,使用 JavaScript 来切换每个动画。
var boxElements = document.getElementsByClassName('box'),
boxElementsLength = boxElements.length,
i;
for (i = 0; i < boxElementsLength; i++) {
boxElements[i].classList.add('move');
}
上面的代码片段是为所有包含 box
类的元素为其添加 move
类以触发动画。
这样做可以为你的应用提供良好的平衡。 你可以专注于使用 JavaScript 管理状态,只需在目标元素上设置适当的类,让浏览器处理动画。 如果沿着这条路线前进,你可以在元素上监听 transitionend
事件,但前提是放弃旧版 Internet Explorer 的支持:
监听 transitionend
触发的事件如下所示:
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 动画,你可以在每一步完全控制元素的样式。 这意味着你可以放慢动画速度,暂停动画,停止它们,翻转它们,并根据需要操纵元素。 如果你正在构建复杂的面向对象的应用程序,这尤其有用,因为你可以正确地封装你想要的动画行为。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具Fundebug。
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 过渡效果的图示:
随着时间增加,值等比增加,使用 linear 动效,会让动画不自然,一般来说,避免使用 linear 动效。
以下是如何实现简单的线性动画:
transition: transform 500ms linear;
Ease-out 动画
如前所述,与线性动画相比,easing out
动画开始时快,结束时候间慢,过渡效果的图示如下:
一般来说,easing out
过渡效果是最适合做界面体验的,因为快速地启动会给人以快速响应的动画的感觉,而结束时让人感觉很平滑这得归功于不一致的移动速度。
有很多方法可以实现 ease-out 效果,但最简单的是 CSS 中的 ease-out
关键字:
transition: transform 500ms ease-out;
Ease-in 动画
和 ease-out
动画相反-开始时快,结束时候间慢,过渡效果图如下:
与 ease-out
动画相比, ease-in
可能会让人感到不寻常,由于启动缓慢给人以反应卡顿的感觉,因此会产生一种无反应的感觉。 动画结束很快也会产生一种奇怪的感觉,因为整个动画正在加速,而现实世界中的物体在突然停止时往往会减速。
和 ease-out
和 linear
动画类似,使用 CSS 关键字来实现 ease-in 动画:
transition: transform 500ms ease-in;
Ease-in-out 动画
该动画为 ease-in 和 ease-out 的合集,过渡效果图如下:
不要使用太长的动画持续时间,因为它们会让你的 UI 感觉没有响应。
用 ease-in-out
CSS 关键字来实现 ease-in-out
动画:
transition: transform 500ms ease-in-out;
自定义 easing
你也可以定义自己的 easing
曲线,这可以更好地创建自己想要的动画效果。
实际上, ease-in
,linear
及 ease
关键字映射到预定义 贝塞尔曲线 ,可以在 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)。
让我们看看贝塞尔曲线的工作原理。 贝塞尔曲线需要四个值,或者更准确地说它需要两对数字。 每对描述立方贝塞尔曲线控制点的 X
和 Y
坐标。贝塞尔曲线的起点有一个坐标 (0, 0)
,结束坐标是 (1, 1)
。 你可以设置两个对号,两个控制点的 X
值必须在 [0,1]
范围内,并且每个控制点的 Y
值可以超过 [0,1] 限制,尽管规定不清楚多少。
即使每个控制点的 X
和 Y
值稍有变化,也会得到完全不同的曲线。让我们看两张贝塞尔曲线的图,两张图相近但坐标的控制结点却不同。
和
如您所见,两张图有很大的不同, 第一个控制点矢量差为 (0.045,0.183)
矢量差,而第二控制点矢量差为 (-0.427, -0.054)
。
第二条曲线的样式为:
transition: transform 500ms cubic-bezier(0.465, 0.183, 0.153, 0.946);
前两个数字是第一个控制点的 X
和 Y
坐标,后两个数字是第二个控制点的 X
和 Y
坐标。
性能优化
当你在使用动画的时候,你应该维持 60 帧每秒,否则会影响用户体验。
和世界上的其他事物一样,动画也会有性能的开销。一些属性的动画性能开销相比其它属性要小。例如,为元素的 width
和 height
做动画会更改其几何结构并且可能会造成页面上的其它元素移动或者大小的改变,这个过程称为布局。我们在之前的一篇文章 中更详细地讨论了布局和渲染。
通常,你应该避免动画触发布局或重绘的属性。 对于大多数现代浏览器,这意味着把动画局限于 opacity
和 transform
属性。
Will-change
你可以使用 will-change 知浏览器你打算更改元素的属性,这允许浏览器在进行更改之前进行最适当的优化。但是,不要过度使用 will-change
,因为这样做会导致浏览器浪费资源,从而导致更多的性能问题。
will-change
用法如下:
.box {
will-change: transform, opacity;
}
该属性在 Chrome, Firefox,Opera 得到很好的兼容。
JavaScript 动画和 CSS 动画该如果抉择
- 根据 Google Developer,渲染线程分为 主线程 (main thread) 和 合成线程 (compositor thread)。如果 CSS 动画只是改变
transforms
和opacity
,这时整个 CSS 动画得以在 合成线程 完成(而JS动画则会在 主线程 执行,然后触发合成线程进行下一步操作),在 JS 执行一些昂贵的任务时,主线程繁忙,CSS 动画由于使用了合成线程可以保持流畅 - 在许多情况下,也可以由合成线程来处理
transforms
和opacity
属性值的更改。 - 对于帧速表现不好的低版本浏览器,CSS3可以做到自然降级,而JS则需要撰写额外代码。
- CSS动画有天然事件支持(TransitionEnd、AnimationEnd,但是它们都需要针对浏览器加前缀),JS则需要自己写事件。
- 如果有任何动画触发绘画,布局或两者,则需要 “主线程” 才能完成工作。 这对于基于 CSS 和 JavaScript 的动画都是如此,布局或绘制的开销可能会使与 CSS 或 JavaScript 执行相关的任何工作相形见绌,这使得问题没有实际意义。
- CSS3有兼容性问题,而JS大多时候没有兼容性问题。
总结
如果动画只是简单的状态切换,不需要中间过程控制,在这种情况下,css 动画是优选方案。它可以让你将动画逻辑放在样式文件里面,而不会让你的页面充斥 Javascript 库。然而如果你在设计很复杂的富客户端界面或者在开发一个有着复杂 UI 状态的 APP。那么你应该使用 js 动画,这样你的动画可以保持高效,并且你的工作流也更可控。所以,在实现一些小的交互动效的时候,就多考虑考虑 CSS 动画。对于一些复杂控制的动画,使用 javascript 比较可靠。
原文:
https://blog.sessionstack.com...
关于Fundebug
Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了9亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!
JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能的更多相关文章
- How Javascript works (Javascript工作原理) (十三) CSS 和 JS 动画底层原理及如何优化其性能
个人总结:读完这篇文章需要20分钟. 这是 JavaScript 工作原理的第十三章. 概述 正如你所知,动画在创建令人叹服的网络应用中扮演着一个关键角色.由于用户越来越注重用户体验,商户开始意识到完 ...
- JavaScript 工作原理之十三-CSS 和 JS 动画底层原理及如何优化其性能
原文请查阅这里,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland. 本系列持续更新中,Github 地址请查阅这里. 这是 JavaScript 工作原理的第十三章. 概述 正如你 ...
- java gc的工作原理、如何优化GC的性能、如何和GC进行有效的交互
java gc的工作原理.如何优化GC的性能.如何和GC进行有效的交互 一个优秀的Java 程序员必须了解GC 的工作原理.如何优化GC的性能.如何和GC进行有效的交互,因为有一些应用程序对性能要求较 ...
- 深入研究Node.js的底层原理和高级使用
深入研究Node.js的底层原理和高级使用
- CSS VS JS动画,哪个更快[译]
英文原文:https://davidwalsh.name/css-js-animation 原作者Julian Shapiro是Velocity.js的作者,Velocity.js是一个高效易用的js ...
- css与 js动画 优缺点比较
我们经常面临一个抉择:到底使用JavaScript还是CSS动画,下面做一下对比 JS动画 缺点:(1)JavaScript在浏览器的主线程中运行,而主线程中还有其它需要运行的JavaScript脚本 ...
- CSS 和 JS 动画哪个更快
基于Javascript的动画暗中同CSS过渡效果一样,甚至更加快,这怎么可能呢?而Adobe和Google持续发布的富媒体移动网站的性能可媲美本地应用,这又怎么可能呢? 本文逐一遍览了基于Javas ...
- 如何编写高质量的js代码--底层原理
转自: 如何编写高质量的 JS 函数(1) -- 敲山震虎篇 本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/7lCK9cHmunvYlbm ...
- js事件底层原理探究
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
随机推荐
- python scrapy框架爬取豆瓣
刚刚学了一下,还不是很明白.随手记录. 在piplines.py文件中 将爬到的数据 放到json中 class DoubanmoviePipelin2json(object):#打开文件 open_ ...
- Java 短信发送
package com.test; import org.apache.commons.httpclient.Header;import org.apache.commons.httpclient.H ...
- Dubbo与Nginx区别
Dubbo的负载均衡已经是服务层面的了,和nginx的负载均衡还在http请求层面完全不同.至于二者哪个优秀,当然没办法直接比较. 涉及到负载均衡就涉及到你的业务,根据业务来选择才是最适合的. dub ...
- 高级Java面试总结1
一.三大框架方面问题 1.Spring 事务的隔离性,并说说每个隔离性的区别 解答:Spring事务详解 2.Spring事务的传播行为,并说说每个传播行为的区别 解答:Spring事务详解 3. ...
- Python爬虫6-利用ProxyHandler设置代理服务器
GitHub代码练习地址:https://github.com/Neo-ML/PythonPractice/blob/master/SpiderPrac09_ProxyHandler.pyProxyH ...
- [Swift]LeetCode191. 位1的个数 | Number of 1 Bits
Write a function that takes an unsigned integer and return the number of '1' bits it has (also known ...
- Linux如何配置想要的JDK
首先我声明下,对于linux系统我到现在学习不到一个星期,所以说很多地方不熟悉,还在学习当中,本文章中有什么技术错误请勿怪哈(PS:我第一次发表博客). 关于linux安装配置jdk,首先我用的是De ...
- Linux中断程序命令
在运行 python 脚本的时候想要中断程序,发现如下情况: ctrl+c 居然无法中断程序! 这时候尝试 ctrl+d 还是毫无效果,最后尝试 ctrl+\: 查看该程序是否还在运行 ps aux ...
- 【从零开始自制CPU之学习篇05】总线
总线定义:总线(Bus)是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线.地址总线和控制总线,分别用来传输数据.数 ...
- Jquery.ajax dataType参数
dataType 类型:String 预期服务器返回的数据类型.如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如 XML MIME 类型就被识别为 XML.在 1.4 ...