CSS трансформационный переход - использование «px» более плавно / производительно, чем «процент» - PullRequest
0 голосов
/ 18 мая 2018

Недавно я пытался улучшить анимацию на своем веб-сайте, в частности раскрывающийся список навигации на мобильных устройствах.

В этой связи я наткнулся на следующий случай, который я надеюсь получить.некоторые более глубокие знания о.

Дело в том, что при переходе / анимации transform: translate3d() кажется, что браузер требует больше вычислений, когда он применяется с использованием % вместо px.Например, в моих тестах кажется, что переход с transform: translate3d(0, 500px, 0) на transform: translate3d(0,0,0) требует меньше вычислений и работает более плавно, чем переход с transform: translate3d(0, 100%, 0).

Обновление: При дальнейшем тестировании я обнаружилчто использование 100vh / 100vw обходит / смягчает проблему использования процентов.Это может быть полезно в тех случаях, когда элемент имеет известную процентную ширину окна или является полной шириной, и, таким образом, повышается производительность.На самом деле кажется, что использование этого значения ведет себя так, как если бы оно было присвоено значению px в Chrome.

Вот пара изображений временной шкалы из каждой анимации.Временные шкалы получены с помощью инструментов Google Dev в разделе «Производительность».Чтобы лучше показать разницу, производительность в Chrome Dev Tools была ограничена до уровня «low-end mobile» (6-кратное замедление ЦП).

Преобразование с использованием процентов:

Transform performance using percent (%)

Преобразование с использованием пикселя (px):

Transform performance using pixel (px)

Как можноИз рисунков видно, что при рендеринге % вместо px происходит гораздо больше рендеринга и рисования.Имеет большой смысл, что браузер должен вычислять процентные значения для каждого кадра (я полагаю?), Но я удивлен, что это занимает намного больше по сравнению с использованием значения в пикселях.

Также обратите внимание, что частота кадров на рисунке, показывающая временную шкалу в процентах, никогда не достигает ~ 60 кадров в секунду, а в среднем составляет около 40 кадров в секунду.

Ниже приведены фрагменты, чтобы повторить случай.Один использует проценты, а другой использует пикс.

$(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 голосов
/ 20 мая 2018

Чтобы еще больше расширить ответ, данный CyperAP, и предложения, сделанные в моем исходном вопросе, я также обнаружил, что использование значений CSS3 vw и vh позволяет обойти проблему, вызванную %.

Этот вариант использования особенно полезен в ситуациях, когда элементу, подлежащему переходу, была задана высота / ширина в зависимости от размера окна - например, если элемент имеет полную ширину (100% / 100vw).

На основе примера из исходного вопроса и вместо использования transform: translate3d(0, 100vh, 0) получен следующий результат временной шкалы (опять же, в Chrome с производительностью, ограниченной "Low end mobile"):

enter image description here

Фрагмент можно посмотреть здесь:

$(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,100vh,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>
0 голосов
/ 18 мая 2018

Правильно ли, что у меня такое поведение (назначение значения в 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>
...