【发布时间】:2018-10-28 18:12:29
【问题描述】:
我最近一直在考虑改进我网站上的动画 - 更具体地说是移动设备上的导航下拉菜单。
在这方面,我偶然发现了以下案例,我希望对此有更深入的了解。
情况是,在转换/动画transform: translate3d() 时,似乎浏览器在使用% 而不是px 应用时需要更多计算。例如。在我的测试中,从transform: translate3d(0, 500px, 0) 到transform: translate3d(0,0,0) 的转换似乎比从transform: translate3d(0, 100%, 0) 转换需要更少的计算并且运行更顺畅。
更新:经过进一步测试,我发现使用100vh/100vw 可以绕过/缓解使用百分比的问题。这在元素具有已知的窗口百分比宽度或全宽的情况下很有用,从而提高了性能。实际上,使用这个值似乎就像在 Chrome 中分配了 px 值一样。
这是每个动画的时间轴图片。时间表是使用“性能”下的 Google 开发工具获得的。为了更好地展示差异,Chrome 开发工具中的性能已被限制为“低端移动”(6 倍 CPU 减速)。
使用百分比转换:
使用像素 (px) 进行变换:
从图像中可以看出,当使用% 而不是px 来确定转换时,似乎正在进行更多的渲染和绘画。浏览器必须计算每一帧的百分比值是很有意义的(我猜?),但令我惊讶的是,与使用像素值相比,它需要更多的时间。
另外请注意,图片中显示百分比时间线的帧速率从未达到 ~60 fps,而是平均在 40 fps 左右。
下面是复制案例的sn-ps。一种使用百分比,一种使用 px。
$(document).on("click", function(){
$(".bb").toggleClass("active");
});
.aa{
height:50px;
background:blue;
position:fixed;
top:0;
width:100%;
}
.bb{
position:fixed;
top:0px;
background:none;
height:100%;
width:100%;
left:0;
transform:translateZ(0);
overflow:hidden;
pointer-events:none;
}
.cc{
height:100%;
transform:translate3d(0,500px,0);
width:100%;
transition:transform .5s ease-in;
background:red;
}
.bb.active .cc{
transform:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Click the document to start animation<p>
<div class="bb">
<div class="cc">
<ul>
<li>Point one</li>
<li>Point two</li>
<li>Point three</li>
<li>Point four</li>
<li>Point five</li>
<li>Point six</li>
<li>Point seven</li>
</ul><ul>
<li>Point one</li>
<li>Point two</li>
<li>Point three</li>
<li>Point four</li>
<li>Point five</li>
<li>Point six</li>
<li>Point seven</li>
</ul>
</div>
</div>
$(document).on("click", function(){
$(".bb").toggleClass("active");
});
.aa{
height:50px;
background:blue;
position:fixed;
top:0;
width:100%;
}
.bb{
position:fixed;
top:0px;
background:none;
height:100%;
width:100%;
left:0;
transform:translateZ(0);
overflow:hidden;
pointer-events:none;
}
.cc{
height:100%;
transform:translate3d(0,100%,0);
width:100%;
transition:transform .5s ease-in;
background:red;
}
.bb.active .cc{
transform:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Click the document to start animation<p>
<div class="bb">
<div class="cc">
<ul>
<li>Point one</li>
<li>Point two</li>
<li>Point three</li>
<li>Point four</li>
<li>Point five</li>
<li>Point six</li>
<li>Point seven</li>
</ul><ul>
<li>Point one</li>
<li>Point two</li>
<li>Point three</li>
<li>Point four</li>
<li>Point five</li>
<li>Point six</li>
<li>Point seven</li>
</ul>
</div>
</div>
为了解决在transform 中使用百分比可能会导致动画性能恶化的“问题”,我提出了以下建议,这可能会提高性能。但是,我有兴趣听取其他意见,因为我不太确定这是否必要以及为什么(?)。
我所做的基本上只是使用 jQuery 以像素而不是百分比来应用 transform 值。对于生产情况,这自然需要在窗口大小调整时进行更新。
这种方法的最终时间表是:
$(document).ready(function(){
var bbWidth = $("#bb .cc").css('transform').split(',')[5].slice(0,-1);
$("#bb .cc").css("transform", "translate3d(0," + bbWidth + "px,0");
$(document).on("click", function(){
$("#bb").toggleClass("active");
});
});
.aa{
height:50px;
background:blue;
position:fixed;
top:0;
width:100%;
}
#bb{
position:fixed;
top:0px;
background:none;
height:100%;
width:100%;
left:0;
transform:translateZ(0);
overflow:hidden;
}
.cc{
height:100%;
transform:translate3d(0,100%,0);
width:100%;
transition:transform .5s ease-in;
background:red;
position:absolute;
top:0;
}
#bb.active .cc{
transform:none!important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="bb">
<div class="cc">
<ul>
<li>Point one</li>
<li>Point two</li>
<li>Point three</li>
<li>Point four</li>
<li>Point five</li>
<li>Point six</li>
<li>Point seven</li>
</ul><ul>
<li>Point one</li>
<li>Point two</li>
<li>Point three</li>
<li>Point four</li>
<li>Point five</li>
<li>Point six</li>
<li>Point seven</li>
</ul>
</div>
</div>
问题:
- 我遇到这种行为是否正确(在
px中赋值比%执行得更好)如果是这样,为什么会发生这种情况?如前所述,它应该对我来说有点道理,但我真的缺乏一些技术/深入的解释。 - 有没有比我的建议更好的方法绕过这个问题?使用
transform: translate()例如如果您“不能”使用%并且同时想要流畅的动画,那么在屏幕外隐藏导航是非常偶然的。
【问题讨论】:
-
不确定是否为 100%,但我猜使用 % 值会使浏览器经常计算这些值,因为它可能会在动画期间发生变化,因为它是一个与 px 不同的相对值。一个很好的测试用例是让动画变慢,并在它调整浏览器大小并查看两者的性能。
-
你试过
transform: translate3d(0, calc(100%), 0);我目前无法测试这个,但也许它会欺骗浏览器使用像素单位?! -
@yoshi 事实上我有,因为我相信与您的想法相同(
calc ()会在浏览器中将其转换为 px 值),遗憾的是相同结果使用%。 Temani,这也是我的想法,也是个好主意 -
您是否尝试过添加 will-change: transform 规则?
-
@vals 是的,这会产生与使用
%的原始案例相同的结果。我猜这也是意料之中的,因为该元素已经通过使用translate3d()“卸载”到 GPU
标签: jquery css css-transitions css-animations css-transforms