我最近一直在研究改进我网站上的动画 - 更具体地说是移动设备上的导航下拉菜单。
在这方面,我偶然发现了以下案例,我希望能够获得更深入的了解。
案例是,在转换/动画transform: translate3d()
时,浏览器在使用%
而不是px
应用时需要进行更多计算。例如。在我的测试中,似乎从transform: translate3d(0, 500px, 0)
过渡到transform: translate3d(0,0,0)
需要更少的计算,并且比从transform: translate3d(0, 100%, 0)
过渡更顺畅。
更新:经过进一步测试,我发现使用100vh
/ 100vw
可以绕过/减轻使用百分比的问题。在元素具有窗口的已知百分比宽度或全宽的情况下,这可以是usefyk,从而改善性能。实际上,似乎使用此值的行为就像在Chrome中分配了px
值一样。
以下是每个动画的时间轴图片。时间线是使用“性能”下的Google Dev工具获得的。为了更好地显示差异,Chrome开发工具的性能受限于“低端移动”(6倍CPU减速)。
使用百分比转换:
使用像素转换(px):
从图像中可以看出,当使用%
而不是px
来确定转换时,似乎有更多渲染和绘画正在进行。浏览器必须计算每个帧的百分比值(我猜?)是很有意义的,但与使用像素值相比,我感到惊讶的是它需要更多的东西。
同样请注意,图片中显示百分比时间轴的帧速率从未达到~60 fps,而是平均约为40 fps。
以下是要复制案例的摘要。有一个使用百分比,一个使用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()
例如如果您“无法”使用%
并且如果您想同时获得平滑的动画,则隐藏屏幕外的导航是非常间接的。 答案 0 :(得分:1)
我遇到这种行为是否正确(在px中分配值的效果优于%)如果是这样,为什么会发生这种情况?如前所述,对我来说它应该是有道理的,但我真的缺乏一些技术/深入的解释。
确实如此。像素是绝对值(即不依赖于任何东西并且表示为“原样”)。百分比是相对值,这意味着它们必须依赖于某些其他值才能产生结果。因此,每次分配一个百分比值时,它必须得到它的相对值才能执行计算。 使用像素进行转换时,您只需更改转换值,但是必须先使用百分比来获取元素的尺寸,然后应用转换。必须为每个动画帧完成这一过程。
要缓解此问题,您必须在动画之前仅重新计算一次元素的尺寸。然后使用!important
覆盖style属性中设置的内容。代码段中的代码正是如此。
另请注意,我添加了resize
侦听器。如果窗口调整大小,则需要这样做,因此您的元素将被隐藏。
$(function(){
var $el = $("#bb");
$(document).on("click", function(){
var height = $el.outerHeight();
$el
.css('transform', 'translateY(' + height + 'px)')
.toggleClass("active");
});
$(window).on('resize', function() {
$el.removeClass('active').removeAttr('style');
});
});
#bb{
position:fixed;
top:0px;
background-color: red;
height:100%;
width:100%;
left:0;
overflow:hidden;
transform: translateY(100%);
transition: transform .5s ease-in;
}
#bb.active
{
transform: translateY(0px) !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>
答案 1 :(得分:0)
为了进一步扩展CyperAP给出的答案以及我在原始问题中提出的建议,我还发现使用CSS3 vh
和%
值会绕过使用{{1}的问题因为。
这个用例在已经根据窗口给出了要转换的元素高度/宽度的情况下特别有用。大小 - 例如如果元素是全角(100%
/ 100vw
)。
根据原始问题中的示例,而使用transform: translate3d(0, 100vh, 0)
会产生以下时间轴结果(同样,在Chrome中,性能仅限于&#34;低端移动设备&#34;):
在这里可以看到片段:
$(document).on("click", function(){
$(".bb").toggleClass("active");
});
&#13;
.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,100vh,0);
width:100%;
transition:transform .5s ease-in;
background:red;
}
.bb.active .cc{
transform:none;
}
&#13;
<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>
&#13;