CSS-анимация подождет
- суббота, 1 апреля 2017 г. в 03:14:58
Перевод статьи Making Animations Wait от Donovan Hutchinson.
Недавно я запустил курс по CSS-анимации для дизайнеров и разработчиков, которые хотят усовершенствовать свои навыки в веб-анимации. Когда я работал над курсом, я столкнулся с проблемой, когда анимация контента начинается до того, как загрузятся файлы. В этой статье описан метод, которым я пользуюсь для решения этой проблемы, и который гарантирует, что вся анимация начнется тогда, когда положено.
Со всеми такое бывало. Например, мы хотим, чтобы наш hero header плавно появлялся при загрузке, поэтому мы добавляем fade-in keyframes, настраиваем анимацию, но при этом анимация начинается до того, как загрузится фоновое изображение этого блока. В результате мы получаем плавно появляющуюся полузагруженную картинку, или даже хуже — наш логотип или заголовок появляется до того, как прогрузится фон.
К счастью, есть способ, который поможет это исправить.
Когда мы заходим на сайт, браузер пытается сделать все так быстро, как может: он загружает и рендерит HTML и CSS и в то же время загружает другие необходимые файлы, такие как картинки.
Этот способ загрузки означает, что мы почти сразу можем увидеть некоторые слои и текстовый контент, но, если на сайте большая шапка журнального типа, то изображение может не прогрузиться вовремя.
Давайте используем некоторые встроенные браузерные трюки, чтобы приостановить анимацию до нужно момента.
Браузеры передают нам удобное javascript-событие load, когда весь контент загружен. Это событие будет срабатывать и для элементов, таких как картинки и скрипты. Мы можем использовать его для управления нашей анимацией.
Мы собираемся использовать скрипт для прослушки события load и CSS-свойство animation-play-state для приостановки анимации пока событие не произойдет.
Вот этот скрипт
document.body.className += " js-loading";
window.addEventListener("load", removeLoadingClass, false);
function removeLoadingClass() {
document.body.className = document.body.className.replace("js-loading", "";);
}
В первой строке к элементу body добавляется класс js-loading.
Затем устанавливается прослушка события.
Когда произойдет событие load, запускается функция removeLoadingClass. В этот момент уже все картинки и другие файлы сайта загружены.
И наконец, функция removeLoadingClass убирает у body класс js-loading.
Этот код нужно разместить в head вашего сайта. Если его грузить из стороннего файла, то CSS может загрузиться раньше, чем сработает этот скрипт, что даст возможность анимации начаться раньше времени.
Можно использовать этот класс для приостановки всех анимаций на странице, пока не загрузится весь контент.
Описанный выше метод ждет пока загрузятся все файлы для страницы. Возможно, вы хотите дождаться только загрузку одного изображения, например для вашего header. К счастью, событие загрузки работает и для каждой картинки отдельно. С этим может помочь подход, описанный в статье Measuring Image Widths in JavaScript.
Мы можем устанавить фокус на одно конкретное изображение.
// Adjust the "querySelector" value to target your image
var img = document.querySelector("img");
document.body.className += " js-loading";
img.addEventListener("load", removeLoadingClass);
function removeLoadingClass() {
document.body.className = document.body.className.replace("js-loading", "");
}
Свойство animation-play-state хорошо поддерживается современными браузерами. Оно говорит браузеру, когда текущую анимацию нужно запустить или остановить. По умолчанию анимация запущена.
Мы можем использовать это свойство, чтобы поставить любую анимация на странице «на паузу», пока загружается контент. Добавим такой код в CSS
.js-loading *,
.js-loading *:before,
.js-loading *:after {
animation-play-state: paused !important;
}
Это код приостанавливает все анимации на странице, пока у body есть класс js-loading. Он применяется также ко все псевдоэлементам: before и: after.
Когда скрипт удаляет класс js-loading у body, CSS-правило не применяется и все анимации запускаются в нужный момент.
Приятный бонус этого метода в том, что не нужно ничего менять в наших стилях.
Это вопрос, который всегда нужно задавать, если мы используем javascript для работы с контентом. Иногда js отказывает. Он может быть выключен. Плагины могут делать непредвиденные вещи. Хотя в большинстве случаев все работает, javascript всегда немного не под нашим контролем, поэтому хорошо бы подумать о том, что произойдет, если он не будет работать так, как ожидается.
В этом случае у нас все хорошо. Если javascript не сработает, то не добавится класс js-loading, и анимация сработает сразу. Это может дать немного странный результат, когда фоновая картинка загружается во время анимации, но это наихудший сценарий и разумный запасной вариант.
Давайте посмотрим на тесте, как это работает. Нам нужна большая картинки. Например, Nasa photo on Unsplash, ее размер около 2 Мб.
Сначала, пока загружается страница, мы будем видеть пустой экран. Чтобы по-настоящему увидеть все в действии, можно использовать встроенное свойство в Chrome. Открываем инспектор, выбираем вкладку Network, затем в выпадающем меню выбираем настройки скорости загрузки. Возьмем Good 3G, который достаточно медленный, чтобы увидеть работу нашего скрипта.
Нажмите «Rerun» на демо-примере, и вы увидите, что анимации не будет, пока не загрузится изображение. Можно попробовать также отключить javascript (и почистить кэш перед перезагрузкой), чтобы увидеть разницу.
Если вы хотите избежать пустой страницы, вы должны использовать какой-нибудь поясняющий текст или анимацию, которая даст пользователям знать, что происходит. Выбор зависит от того, как долго по вашему мнению будет происходить загрузка. Если у вас чрезвычайно большое изображение и ожидание будет более чем 1-2 секунды, то индикатор будет хорошим вариантом.
С другой стороны, возможно лучше сжать посильнее изображение или уменьшить его так, чтобы загрузка была быстрее. Экспериментируйте и смотрите, какой вариант будет лучше для вас.