学向勤中得,萤窗万卷书。这篇文章主要讲述#私藏项目实操分享# CSS3 实现“完全体”的 60 FPS 动画效果,CodeReview 同事直呼:细节!相关的知识,希望能为你提供帮助。
?前言小叙FPS 全称:Frames per second,即 【每秒帧数】 的意思。通常来讲,当动画的每秒帧数低于 12 (即 12 FPS 以下)时,我们的大脑就能快速从动画中区分出一些静止的图片,所以此时的动画并不是无缝动画。
一旦播放速率(每秒帧数)达到 16-24 FPS 时,大脑就会认为这些画面是连续移动的场景,看起来就是影片的效果了(大部分数字电影拍摄是每秒 24 帧)。所以,我们可以大致了解到:FPS 越高,画面越流畅!
明白这些后,我们可以便可开始本篇正题了:_CSS3 实现 60 FPS 的动画效果!_
常规操作
本瓜知道你会说:“CSS3 动画,有手就行!”
知道我们的目标是实现下图动画效果时,
你信手拈来,一顿操作!很棒,恭喜你能轻松写出以下这段超级常规的 CSS3 动画~
<
div class="layout">
<
div class="app-menu">
<
/div>
<
div class="header">
<
div class="menu-icon">
<
/div>
<
/div>
<
/div>
.app-menu
left: -300px;
transition: left 300ms linear;
.app-menu-open .app-menu
left: 0px;
transition: left 300ms linear;
它的实现效果:
你确实做到了,但,到此为止吗?
这次我们选择:不止于此!
于是,打开控制台 Performance Ctrl+E 进行录制这段动画来进一步分析分析。
我们可以看到它的 Timeline 中 FPS 指标(绿色部分)
* 绿色部分的高点表示以 60 FPS 进行渲染,低点则表示以低于 60 FPS 进行渲染;
我们发现了它存在问题:
* 红色条表示卡顿;
1. 绿色部分的高度并不一致,说明 FPS 不稳定;
2. 绿色部分有相当一部分处在低点,说明 FPS 不流畅;
3. 存在很多红色条,说明动画很卡;
所以,结论是:我们这种方法实现的 CSS3 动画,并不流畅!!
我们期望的是:高度齐平,绿色都处于高点,红色条越少越好。 别方,带着期望,继续往下看!
进阶操作你非常棒,并且异于常人!!你想到了使用 Transform 来实现!! CSS 代码:
.app-menu
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
transition: transform 300ms linear;
.app-menu-open .app-menu
-webkit-transform: none;
transform: none;
transition: transform 300ms linear;
实现效果:
控制台看下 Timeline:
的确不一样了,跟【常规操作】中的 Timeline 图作比,高度都更加齐平了!更多绿色部分处于高点了!红色条也减少了!
这表示我们的动画效果,更流畅了!
高级操作噢噢噢,原来你是位高级前端,你还会这样 will-change 这样高级的操作!CSS 代码:
.app-menu
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
transition: transform 300ms linear;
will-change: transform;
实现效果:
控制台看下 Timeline:
天呐噜!
相较于【进阶操作】,我们更加接近目标:高度基本齐平了!绿色位置绝大部分都处在高位!红条减的更少了!
这么厉害的嘛?不妨再往下看!
顶级操作
至此,你的手中还有牌吗?
或许我们还能从 DOM 结构找找突破口!将前文的 DOM 改造成:
<
div class="menu">
<
div class="app-menu">
<
/div>
<
/div>
<
div class="layout">
<
div class="header">
<
div class="menu-icon">
<
/div>
<
/div>
<
/div>
在 layout 区域之外创建 menu,然后使用 js 中的 transitionend 函数来监听,使 menu--animatable 类在过渡时间结束时被移除。
// js
function toggleClassMenu()
myMenu.classList.add("menu--animatable");
if(!myMenu.classList.contains("menu--visible"))
myMenu.classList.add("menu--visible");
else
myMenu.classList.remove(menu--visible);
function OnTransitionEnd()
myMenu.classList.remove("menu--animatable");
var myMenu = document.querySelector(".menu");
var oppMenu = document.querySelector(".menu-icon");
myMenu.addEventListener("transitionend", OnTransitionEnd, false);
oppMenu.addEventListener("click", toggleClassMenu, false);
myMenu.addEventListener("click", toggleClassMenu, false);
// 完整 css
menu
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
z-index: 150;
.menu--visible
pointer-events: auto;
.app-menu
background-color: #fff;
color: #fff;
position: relative;
max-width: 400px;
width: 90%;
height: 100%;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5);
-webkit-transform: translateX(-103%);
transform: translateX(-103%);
display: flex;
flex-direction: column;
will-change: transform;
z-index: 160;
pointer-events: auto;
.menu--visible .app-menu
-webkit-transform: none;
transform: none;
.menu--animatable .app-menu
transition: all 130ms ease-in;
.menu--visible.menu--animatable.app-menu
transition: all 330ms ease-out;
.menu:after
content: ;
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.4);
opacity: 0;
will-change: opacity;
pointer-events: none;
transition: opacity 0.3s cubic-bezier(0,0,0.3,1);
.menu--visible.menu:after
opacity: 1;
pointer-events: auto;
它的 Timeline:
这就是 CSS3 实现 60 FPS动画的顶级操作!
高度全部齐平!!全部处在高位!!没有红条!!
这是完美的 FPS 动画!如丝般顺滑!
你做到了!(??????)??
原理探寻我们在此做简单回顾:级别|实现核心方式|FPS 绿块效果|动画顺滑程度
-|-|-|-
常规操作|transition: left 300ms linear;
|高度不齐平、较多处于低点、很多红条|30% 顺滑
进阶操作|transition: transform 300ms linear;
|高度比较齐平、较少处于低点、较少红条|60% 顺滑
高级操作|will-change: transform;
|高度基本齐平、很少处于低点、很少红条|80% 顺滑
顶级操作|transitionend 函数
|高度完全齐平、全部处于高点、没有红条|100% 顺滑
原理?原理还得回归底层,来看看浏览器的渲染机制!
上图是浏览器渲染的关键步骤,相信大家都很熟悉:
第 4 步“合成”给了我们很多操作空间:我们可以使用 transform 和 opacity 两个属性实现四种最常用的动画:
在第 4 步操作为什么具有魔法呢?
笨蛋,当然是避免重绘、回流增加渲染负担啦~所以,我们的进阶操作控制 transform 比常规操作控制 left 属性更优!而高级操作中的 will-change 能告知浏览器元素会有哪些变化,这样浏览器能在变化之前做好优化准备工作,将一部分复杂计算提前准备好,所以页面的反应更加快速灵敏。顶级操作中改造分离 DOM,然后用 JS控制,手动添加 menu--animatable 类,然后用到 transitionend 事件 会在 CSS transition 结束后触发,移除 menu--animatable 类。实现完全体的 60FPS 动画!
通常来说,我们能做到进阶操作或高级操作中的实现应该就够了,如果在特殊情景下,如对 FPS 要求特别高,我们再开拓思路,启用顶级操作!(顶级操作是把宝刀,一般不拿出来~)
写在结尾我们都知道编码习惯非常重要,但同时又一直苦于思考,如何将一些原理知识与实际编码结合?!
而本篇是基于浏览器渲染原理,对 CSS3 动画的一个很好结合实践!
CodeReview 时,同事都直呼:细节!
“秒啊~ 我理解的原理知识用来面试,你理解的原理知识用来工作中日常编码,细节!高级!”ok,以上便是本次分享 都看到这儿了,点个赞鼓励鼓励吧 b( ̄▽ ̄)d
参考:
【#私藏项目实操分享# CSS3 实现“完全体”的 60 FPS 动画效果,CodeReview 同事直呼(细节!)】
推荐阅读
- Azkaban工作流调度
- #yyds干货盘点# redis | 十七redis之订阅发布
- #yyds干货盘点#--kubernetes集群搭建
- #星光计划2.0#Openharmony单元测试1: 测试用例指导大全
- 讲一下 Java 创建一个对象的过程。????#yyds干货盘点#
- 大厂面试高频算法题,这10道题必须拿捏!
- Flutter 专题44 图解矩阵变换 Transform 类#yyds干货盘点#
- 图解带你掌握`JVM`运行时核心内存区
- Jenkins + Gitlab + harbor + Kubernetes实现CI/CD