НовостиАдминистрированиеУправления хостингомАрхив
09 апреля 2015

Введение в свойство CSS «will-change»

В этой статье мы рассмотрим свойство CSS will-change, что это такое, как и когда следует его использовать и как не следует его использовать. Существует достаточно большое количество технической документации по свойству will-change. Эта статья служит в качестве обзора важных моментов и включает несколько кратких примеров.

Основы

Сегодня многие разработчики пользовательских интерфейсов активно используют CSS3 переходы, трансформации и анимации для создания нового уровня интерактивности приложений, которая раньше основывалась на библиотеках JavaScript или Flash. На данный момент мы способны выполнять аккуратные и красивые анимации с минимальным использованием CSS. Если вы экспериментировали с использованием этих свойств CSS3, вы наверняка встречали такие термины, как CPU (ЦП), GPU (ГП) и аппаратное ускорение. Давайте вкратце повторим эти понятия:

  1. ЦП или центральный процессор это аппаратная часть, которая обрабатывает практически каждую операцию компьютера. Также он известен как материнская плата.
    1. ГП или графический процессор это аппаратная часть, связанная с обработкой и отображением графики. ГП создан для выполнения сложных графических вычислений и разгрузки некоторый тяжелых процессов с ЦП.
    2. Аппаратное ускорение это общий термин для выгрузки процессов ЦП на другие предназначенные для этого аппаратные части. В мире CSS переходов, трансформаций и анимации это подразумевает, что мы перегружаем процесс на ГП, таким образом ускоряя его. Это происходит путем переноса элемента на свой собственный слой, где он может отображаться независимо, при этом будучи анимированным.

Как это улучшает эффективность и качество анимации? Будучи новичками, работающими в браузерах на базе WebKit, мы часто видели мерцание при выполнении некоторых операций CSS, в частности двухмерных трансформаций и анимации. В прошлом, мы избавлялись от этого немного обманывая браузер. Мы могли заставить браузер думать, что он выполняет трехмерную трансформацию, при этом перегружая операцию на ГП. А все потому, что трехмерные трансформации автоматически переносятся туда. В результате этого получалась подобная хитрость:

.accelerate {
 -webkit-transform: translate3d(0, 0, 0);
}

Существует еще несколько таких хитростей, но в большинстве случаев нам достаточно и этого. Однако, это хак, и это именно тот случай, когда свойство will-change может нам неплохо помочь, но при правильном использовании. Давайте изучим его.

Что такое will-change?

Согласно документации W3C:

Свойство CSS will-change позволяет автору информировать UA заранее о том, какие типы изменений могут произойти с элементом. Это позволяет UA оптимизировать способ обработки элемента заранее, выполняя потенциально затратную работу, подготавливаясь к анимации до того, как анимация на самом деле начнется.

Это означает, что вместо того, чтобы насильно запускать наши трансформации на ГП через хак трехмерной трансформации, мы можем теперь использовать выделенное свойство для информирования браузера, что он должен готовиться к будущим изменениям, оптимизируя и выделяя память соответствующим образом. Звучит неплохо, неправда ли? Прежде чем радоваться, нам нужно понять, как использовать will-change.

Как используется will-change?

Свойство will-change является эффективным только в случае использования в определенное время. Мы не можем использовать что-то вроде will-change: transform для уже трансформирующегося элемента это просто не имеет смысла. Сара Соуэйдан очень подробно рассказывает об этом в блоге Opera, поэтому не забудьте его почитать. Но все же здесь следует отметить следующие моменты:

  1. Нас интересует использование этого свойства, чтобы позволить браузеру заранее знать о том, какие изменения будут происходить с элементом.
    1. Это позволяет браузеру заранее выполнить соответствующую оптимизацию, что в конечном итоге приводит к более быстрому и четкому отображению.
    2. Как упоминалось ранее, браузеру нужно знать заранее о происходящих изменениях.

Это означает, что мы должны заранее продумать, когда готовить браузер к изменениям. Помня эти пункты, давайте рассмотрим пример, который не принесет никакого результата:

.will-change:active {
 will-change: transform;
 transition: transform 0.3s;
 transform: scale(1.5);
}

Здесь изменение уже происходит в момент, когда мы информируем браузер, полностью исключая весь смысл свойства will-change. Если мы хотим, чтобы браузер знал заранее, когда ожидать изменений, мы должны информировать его в нужный момент.

Чтобы элемент получил статус active, на него нужно навести курсор. Мы можем сделать это следующим образом:

.will-change {
 transition: transform 0.3s;
}
.will-change:hover {
 will-change: transform;
}
.will-change:active {
 transform: scale(1.5);
}

Этот небольшой пример дает нам понимание о мыслительном процессе, необходимом для правильного использования свойства will-change. Прежде чем мы продолжим рассматривать другие примеры, нам нужно запомнить несколько важных фактов.

Браузеры по сути делают все возможное, чтобы оптимизироваться и приготовиться к изменениям. Браузеры могут удалять некоторые оптимизации, как только они смогут освободить память. Использование свойства will-change непосредственно по отношению элементу говорит браузеру, что рассматриваемый элементы всегда находится в состоянии скорого изменения. Это заставляет браузер сохранять оптимизацию, таким образом увеличивая потребление памяти. Помня об этом, мы должны найти способ добавлять и удалять свойство will-change в нужные моменты времени. Первый пример делает это за нас, так как свойство добавляется только при наведении курсора. Но что если мы хотим, чтобы трансформация происходила непосредственно при наведении курсора? Наверное, вы уже хотите это сделать:

.will-change {
 will-change: transform;
 transition: transform 0.3s;
}
.will-change:hover {
 transform: scale(1.5);
}

Это приведет к увеличению потребления памяти, так как мы заставляем браузер всегда думать, что элемент вот-вот изменится. Мы можем обойти это, вместо этого учитывая приближение события в родительском контейнере:

.will-change-parent:hover .will-change {
 will-change: transform; 
}
.will-change {
 transition: transform 0.3s; 
}
.will-change:hover {
 transform: scale(1.5); 
} 
\n

Это добавляет оптимизацию, когда мышь попадает на родительский контейнер, и удаляет, когда мышь убирается. Тем не менее, это также подразумевает, что каждый раз, когда мышь попадает на родительский контейнер, браузер может ожидать, что элемент изменится. Это не обязательно будет так, и представляет идеальный пример того, как можно легко испортить этот свойство.

Создание полноэкранного слайд-шоу или кинеографа в CSS это пример того, когда есть смысл в прямом использовании. Слайды всегда должны изменяться, поэтому можно сделать что-то вроде этого:

.slide {
 will-change: transform;
}

Никогда не забывайте удалять свойство will-change, если вы закончили его использовать. Как уже говорилось ранее, оптимизация браузера это затратный процесс, поэтому, если использовать его неправильно, он может иметь побочные действия. Мы можем справиться с этим с помощью JavaScript, а потому давайте обратимся к скрипту MDN, чтобы построить наглядный пример. Представьте, что у нас есть элемент с классом element, и когда мы нажимаем на него, он начинает трансформироваться. Наш CSS может выглядеть следующим образом:

.element {
 transition: transform 0.5s;
}
.element.clicked {
 transform: scale(1.5);
}

Если мы хотим сообщить браузеру, чтобы он готовился оптимизироваться для изменений, которые вот-вот произойдут в ответ на клик по элементу, мы можем сделать это следующим образом:

var el = document.querySelector('.element');
el.addEventListener('mouseenter', hintBrowser);
el.addEventListener('animationEnd', removeHint);
function hintBrowser() {
 this.style.willChange = 'transform';
}
function removeHint() {
 this.style.willChange = 'auto';
}

Конечно, вам нужно будет включить необходимый JavaScript, чтобы добавить корректный класс clicked, когда на элемент будут непосредственно кликать, но вышеприведенный скрипт может помочь вам разобраться в том, как готовить браузер к изменениям, и как освободить память, когда изменения уже закончились. При наведении мыши на элемент добавляется свойство will-change. Когда на него нажимают и происходит трансформация (согласно вашему скрипту), отправляются события анимации. После animationEnd мы удаляем свойство will-change, снова освобождая память.

Поддержка браузеров

Свойство will-change является довольно новым, и на данный момент поддерживается следующими браузерами (согласно Can I Use):

  • Chrome 36 и выше
    • Firefox 36 и выше
    • Opera 24 и выше
    • Android browser 37
    • Chrome для Android 40
    • Opera Mobile 24

Internet Explorer это единственный широко используемый браузер, который его не поддерживает. На момент публикации этой статьи свойство will-change входило в список на рассмотрение .

Заключительные замечания

Свойство CSS will-change может принести как много хорошего, так и много плохого. Это утверждение не имеет целью отпугнуть вас от его использования, а выступает в качестве рекомендации. Нет причин не рассматривать возможность использования этого свойства в ваших современных приложениях, но не забывайте обо всех возможных проблемах, о которых сказано в этой статье. Надеюсь, вы разобрались, что за животное оптимизация браузера, и сможете использовать эти знания в своих дальнейших проектах.

По материалам www.sitepoint.com