使用CSS3实现60FPS的移动端动画

如果您按照我们的提示,您在移动应用程序中使用动画元素会很容易,在其中适当地使用动画元素也会很容易...

虽然每个人都在移动领域使用CSS3动画,但是很多人做的并不正确。开发人员经常无视最佳做法。这是因为人们不了解这些做法存在的原因,以及为什么这些做法会得到强烈认可。

设备规格范围广泛,因此如果您不优化您的代码,很大程度上将会提供一个次级体验。

请记住:一些高端旗舰设备推动外壳的发展,但世界上大多数使用的设备类型与这些规格怪物相比,看起来更像一个带有液晶显示屏的算盘。

我们想帮助并且给予您正确使用CSS3的力量。要做到这一点,首先要了解一些事情。

 

了解时间线

浏览器在渲染和播放元素时执行什么操作?该时间轴称为关键渲染路径:

Critical Rendering Path

要实现平滑的动画,我们需要关注的是改变影响复合步骤的属性,而不是将此压力添加到以前的图层。

1.样式

Styles

浏览器开始计算应用于元素的样式 - 重新计算样式。

2.布局

Layout

在下一层中,浏览器生成每个元素的形状和位置 -  布局。也就是浏览器设置页面属性,如width和height,以及它的margin或left/top/right/bottom。

3.着色

Paint

浏览器将每个元素的像素填充到图层中。指的是这些属性:box-shadow,border-radius,color,background-color等。

4.合成

这是您要执行动画的地方,因为浏览器会将所有图层拖到屏幕上。

Composite

现代浏览器可以很好的支持四种动画风格的属性,使用transform和opacity属性来制作。

  • 位置  - transform:translateX(n)translateY(n)translateZ(n);

  • 缩放  - transform:scale(n);

  • 旋转  - transform:rotate(ndeg);

  • 不透明度  - opacity:n;

 

如何实现每秒60帧

考虑到这一点,现在是时候卷起袖子工作了。

我们从HTML开始吧。我们将创建一个非常简单的结构,并将我们的应用程序菜单放在布局类中。

<div class="layout">
  <div class="app-menu"></div>
  <div class="header">
    <div class="menu-icon"></div>
  </div>
</div>

0?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1

 

错误的方法是这样的

.app-menu {
  left: -300px;
  transition: left 300ms linear;
}

.app-menu-open .app-menu {
  left: 0px;
  transition: left 300ms linear;
}

看到我们改变的属性了吗?你应该避免使用属性的left/top/right/bottom进行转换。那些不会创建流畅的动画,因为它们强制浏览器每次执行布局传递,影响所有子元素。

结果是这样的:

0?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1

这个动画不太顺利。我们检查了DevTools Timeline,看看发生了什么事情,结果是这样的:

DevTools Timeline

绿色区域表示渲染动画花费的时间。

该数据呈现不规则的帧率和缓慢的性能。

“绿色条表示FPS。高一点的表示动画呈现为60 FPS。低一点的表示低于60 FPS。因此,理想情况下,您希望绿色栏在时间轴上始终保持高位。那些红色的条也显示出一个尾巴,所以,另一种方式来衡量你的进步是消除那些红色的尾巴。”

使用变换

.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;
}

transform属性影响的是复合步骤,而不是布局。在这里,我们通知浏览器:我们的图层在动画开始之前是稳定的,所以我们在渲染动画时遇到更少的停顿。

0?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1

这正是Timeline所反映的:

Timeline using transform

结果开始变得更好了,帧率似乎也已经稳定,因此,动画运行也平稳了起来。

在GPU中运行动画

那我们继续吧。要真正让它运行顺利,我们将使用GPU渲染动画。

.app-menu {
  -webkit-transform: translateX(-100%);
  transform: translateX(-100%);
  transition: transform 300ms linear;
  will-change: transform;
}

虽然一些浏览器仍然需要translateZ()或translate3d()作为回调,will-change属性是未来。此属性将元素提升到另一层,因此浏览器不必考虑布局渲染或绘画。

0?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1

看看是不是更顺利了?这是时间线的证明:

Timeline running animations

动画的帧率更加恒定,呈现的也更快。但是开始的时候还是有一长串的架构:起初有点瓶颈。

还记得我们在开始创建的HTML结构吗?我们来看看我们是如何在JavaScript中控制app-menudiv:

function toggleClassMenu() {
  var layout = document.querySelector(".layout");
  if(!layout.classList.contains("app-menu-open")) {
    layout.classList.add("app-menu-open");
  } else {
    layout.classList.remove("app-menu-open");
  }
}
var oppMenu = document.querySelector(".menu-icon");
oppMenu.addEventListener("click", toggleClassMenu, false);

啊哈!问题是由我们将类添加到layout来引起的。这迫使浏览器重新生成我们的样式表,并且影响了渲染性能。

像黄油溶液一样流畅的60FPS

如果我们在视口区域外创建菜单怎么办?将菜单放在一个孤立的区域将确保我们只影响我们希望动画的元素。

所以,我们提出以下HTML结构:

<div class="menu">
  <div class="app-menu"></div>
</div>
<div class="layout">
  <div class="header">
    <div class="menu-icon"></div>
  </div>
</div>

现在我们必须以略微不同的方式来控制菜单的状态。在动画结束时,我们将通过使用JavaScript中的函数来操作我们删除的transitionend函数中的动画。

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);

让我们一起来看看结果。这是一个完整的完全启用CSS3的示例,其中的所有内容都在正确的位置:

.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;
}

0?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1

那么我们看到的时间线是怎样的呢?

Timeline of CSS3 example

每天都是绿色条,。想看一个实例吗?点击这里(http://codepen.io/Onyros/pen/jAJxkW)。

转载于:https://my.oschina.net/u/2306318/blog/869658

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值