如果您按照我们的提示,您在移动应用程序中使用动画元素会很容易,在其中适当地使用动画元素也会很容易...
虽然每个人都在移动领域使用CSS3动画,但是很多人做的并不正确。开发人员经常无视最佳做法。这是因为人们不了解这些做法存在的原因,以及为什么这些做法会得到强烈认可。
设备规格范围广泛,因此如果您不优化您的代码,很大程度上将会提供一个次级体验。
请记住:一些高端旗舰设备推动外壳的发展,但世界上大多数使用的设备类型与这些规格怪物相比,看起来更像一个带有液晶显示屏的算盘。
我们想帮助并且给予您正确使用CSS3的力量。要做到这一点,首先要了解一些事情。
了解时间线
浏览器在渲染和播放元素时执行什么操作?该时间轴称为关键渲染路径:
要实现平滑的动画,我们需要关注的是改变影响复合步骤的属性,而不是将此压力添加到以前的图层。
1.样式
浏览器开始计算应用于元素的样式 - 重新计算样式。
2.布局
在下一层中,浏览器生成每个元素的形状和位置 - 布局。也就是浏览器设置页面属性,如width和height,以及它的margin或left/top/right/bottom。
3.着色
浏览器将每个元素的像素填充到图层中。指的是这些属性:box-shadow,border-radius,color,background-color等。
4.合成
这是您要执行动画的地方,因为浏览器会将所有图层拖到屏幕上。
现代浏览器可以很好的支持四种动画风格的属性,使用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>
错误的方法是这样的
.app-menu {
left: -300px;
transition: left 300ms linear;
}
.app-menu-open .app-menu {
left: 0px;
transition: left 300ms linear;
}
看到我们改变的属性了吗?你应该避免使用属性的left/top/right/bottom进行转换。那些不会创建流畅的动画,因为它们强制浏览器每次执行布局传递,影响所有子元素。
结果是这样的:
这个动画不太顺利。我们检查了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属性影响的是复合步骤,而不是布局。在这里,我们通知浏览器:我们的图层在动画开始之前是稳定的,所以我们在渲染动画时遇到更少的停顿。
这正是Timeline所反映的:
结果开始变得更好了,帧率似乎也已经稳定,因此,动画运行也平稳了起来。
在GPU中运行动画
那我们继续吧。要真正让它运行顺利,我们将使用GPU渲染动画。
.app-menu {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
transition: transform 300ms linear;
will-change: transform;
}
虽然一些浏览器仍然需要translateZ()或translate3d()作为回调,will-change属性是未来。此属性将元素提升到另一层,因此浏览器不必考虑布局渲染或绘画。
看看是不是更顺利了?这是时间线的证明:
动画的帧率更加恒定,呈现的也更快。但是开始的时候还是有一长串的架构:起初有点瓶颈。
还记得我们在开始创建的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;
}
那么我们看到的时间线是怎样的呢?
每天都是绿色条,。想看一个实例吗?点击这里(http://codepen.io/Onyros/pen/jAJxkW)。