CSS转换过渡 - 使用'px'比'百分比'

时间:2018-05-18 10:14:31

标签: jquery css css-transitions css-animations css-transforms

我最近一直在研究改进我网站上的动画 - 更具体地说是移动设备上的导航下拉菜单。

在这方面,我偶然发现了以下案例,我希望能够获得更深入的了解。

案例是,在转换/动画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减速)。

使用百分比转换:

Transform performance using percent (%)

使用像素转换(px):

Transform performance using pixel (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值。对于生产案例,自然需要更新窗口大小。

此方法的最终时间表是:

enter image description here

$(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()例如如果您“无法”使用%并且如果您想同时获得平滑的动画,则隐藏屏幕外的导航是非常间接的。

2 个答案:

答案 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;):

enter image description here

在这里可以看到片段:

&#13;
&#13;
$(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;
&#13;
&#13;

相关问题