最近我一直在尝试提高网站动画效果,具体来说是移动设备上的导航下拉菜单。
在这个过程中,我发现了一个问题,希望能够深入了解一下。就是当使用%
而不是px
应用transform: translate3d()
进行过渡/动画时,浏览器需要更多的计算。例如,在我的测试中,从transform: translate3d(0, 500px, 0)
到transform: translate3d(0,0,0)
的转换需要更少的计算,并且运行更流畅,而从transform: translate3d(0, 100%, 0)
的过渡则需要更多计算。
更新:进一步的测试表明,使用100vh
/100vw
可以避免/缓解使用百分比时出现的问题。这在元素具有已知窗口百分比宽度或为全宽度的情况下非常有用,可以提高性能。实际上,在 Chrome 中,使用此值的行为就像将其分配为px
值。
以下是每个动画时间轴的几张图片。时间轴是在 Google Dev 工具下的“性能”选项卡中获取的。为了更好地显示性能差异,Chrome Dev 工具将性能限制为“低端移动设备”(6 倍 CPU 减速)。
使用百分比进行变换:
使用像素 (px) 进行转换:
从这些图片中可以看出,使用%
来确定变换时,渲染和绘画的工作量要比使用px
更多。浏览器必须为每个帧计算百分比值(我猜?),这很有道理,但与使用像素值相比,它需要更多的工作量,这让我感到惊讶。另外请注意,显示百分比时间轴的图片中帧率从未达到60 fps,而是平均约40 fps。
以下是复制此情况的代码片段。其中一个使用百分比,另一个使用像素。
$(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()
将导航隐藏在屏幕外是非常具体的。
transform: translate3d(0, calc(100%), 0);
吗?我目前无法测试,但也许它可以欺骗浏览器使用像素单位?! - Yoshicalc()
会在浏览器中将其转换为像素值,但不幸的是结果和使用百分比一样。Temani,这也是我的想法,是个好主意。 - Chri.stranslate3d()
已经将元素“卸载”到 GPU 上了。 - Chri.s