Переход с преобразованием CSS - использование "px" более плавное/результативное, чем "процент"
Недавно я изучал улучшение анимации на своем веб-сайте - более конкретно, раскрытие навигации на мобильных устройствах.
В этой связи я наткнулся на следующий случай, о котором я надеюсь получить более глубокие знания.
Дело в том, что при переходе/анимации transform: translate3d()
кажется, что браузер требует больше вычислений, когда он применялся с использованием %
а не px
. Например, в моих тестах кажется, что переход из transform: translate3d(0, 500px, 0)
для transform: translate3d(0,0,0)
требует меньше вычислений и работает более плавно, чем переход из transform: translate3d(0, 100%, 0)
,
Обновление: после тестирования я обнаружил, что использование 100vh
/100vw
обходит /100vw
проблему использования процентов. Это может быть usefyk в случаях, когда элемент имеет известную процентную ширину окна или имеет полную ширину и тем самым улучшает производительность. На самом деле кажется, что использование этого значения ведет себя так, как если бы он был присвоен значением px
в Chrome.
Вот несколько фотографий временной шкалы из каждой анимации. Временные графики получены с помощью инструментов Google Dev в разделе "Производительность". Чтобы лучше показать разницу, производительность была ограничена в Chrome Dev Tools до "младшего мобильного" (6-кратное снижение производительности процессора).
Преобразование с использованием процентов:
Преобразование с использованием пикселя (px):
Как видно из изображений, кажется, что при рендеринге и рисовании происходит гораздо больше рендеринга и рисования при использовании %
а не px
чтобы определить преобразование. Имеет смысл, что браузеру приходится вычислять процентные значения для каждого кадра (я думаю?), Но я удивлен, что это занимает гораздо больше, по сравнению с использованием значения пикселя.
Также обратите внимание, что фреймворки на снимке, показывающие временную шкалу процента, никогда не достигают ~ 60 кадров в секунду, но довольно усредняют около 40 кадров в секунду.
Ниже приведены фрагменты для повторения дела. Там один использует процент и один, используя 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>
Ответы
Ответ 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>
Ответ 2
Чтобы еще больше расширить ответ, полученный CyperAP, и предложения, сделанные в моем первоначальном вопросе, я также обнаружил, что использование значений CSS vw
и vh
обходит проблему, вызвав причину %
.
Этот прецедент особенно полезен в ситуациях, когда для элемента, подлежащего переходу, была задана высота/ширина на основе размера окна, например, если элемент имеет полную ширину (100%
/100vw
).
На основе примера из исходного вопроса и вместо этого с помощью transform: translate3d(0, 100vh, 0)
дает следующий результат временной шкалы (опять же, в Chrome с производительностью, ограниченной "Low end mobile"):
Фрагмент можно увидеть здесь:
$(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>