Всё чаще среди веб-разработчиков поднимается тема возможностей CSS анимаций (transition/animation), практически на каждой конференции по клиентской разработке можно услышать о потрясающих преимуществах новой технологии.
Производительность и гибкость CSS анимаций позволяет творить удивительные вещи, но можно ли уже использовать эти новые возможности в силу их нестабильности и незрелости на реальных больших проектах?
В этом посте мы расскажем, почему так важно начинать использовать новые технологии клиентской разработки уже сегодня и о трудностях, которые могут ждать вас на пути.
Состояние спецификации
Модули CSS transitions и animations в W3C по-прежнему находится в состоянии “working draft”, но Firefox, Opera и Internet Explorer 10 уже откинули префиксы для этих свойств. Избавление от префиксов означает, что производители браузеров уже уверены в стабильности технологии и рекомендуют её к активному использованию.
Если большие игроки до сих пор боялись улучшать user experience пользователей за счет анимаций, ссылаясь на плохую производительность JavaScript, то сейчас самое время пересмотреть свой подход разработки интерфейсов и начать использовать возможности CSS3.
Информационный голод
Из-за отсутствия опыта внедрения CSS анимаций в живые проекты в сети крайне мало информации о реализациях бытовых задач. Все по-прежнему используют JavaScript решения, боясь выступить в роли пионеров отрасли.
Еще больше приходится страдать, сталкиваясь со специфичными багами, появляющимися из-за столкновения множества факторов, таких как, огромная величина DOM дерева, количество анимируемых блоков на странице, высокая вложенность и множество наслоений блоков друг на друга. Пробуя справляться с такой нагрузкой, браузеры во всю используют свои алгоритмы оптимизации, но, порой, это приводит к необъяснимым багам.
Последнее время мы часто встречаемся с браузерными багами, о которых нет ни слова в сети. Вследствие чего приходится самим исследовать проблему, писать баг-репорты и искать необычные решения для её устранения.
Чем раньше большие игроки начнут использовать новые технологии клиентской разработки, тем быстрее будет развиваться отрасль веб-разработки.
CSS анимации в реальном мире
Давайте посмотрим, какие веб-проекты осмелились укротить новую технологию и не побоялись выступить пионерами в отрасли:
ВКонтакте частично использует анимацию на простых, маленьких блоках, часто выбирая JavaScript анимацию вместо CSS, даже для простых анимаций opacity и в переходах цвета текста. Поиск по стилям проекта выдаёт 17 вхождений transition (не считая свойства с префиксами).
На Facebook анимации тоже не прижились, по всем стилям найдено только пять вхождений transition, и единственная попавшаяся на глаза анимация последнего отосланного сообщения сделана на JS.
Ребята из Google+, видимо, принципиально не используют анимации (наверное, из-за проблем Chrome в работе с анимациями :), нашлось только 3 вхождения transition. Поиск “animation” выдал только одно вхождение в Goolge+.
На момент написания статьи в стилях Одноклассников — 140 вызовов transition и 4 animation, учитывая, что часть анимаций стандартизирована и переиспользуется во многих местах.
Интересное замечание — с момента написания первой версии статьи прошло пару месяцев, за это время количество анимаций на перечисленных проектах не выросло, кроме Одноклассников — количество анимаций в нашей социальной сети выросло практически в 3 раза.
Что стоит анимировать
Чем больше мы приближаем работу интерфейса к реальности, тем понятней он становится для пользователя. В жизни практически ничего не происходит мгновенно — открывая дверь, или закрывая лаптоп, мы наблюдаем кучу промежуточных состояний, а не резкое “открыто/закрыто”, как это происходит в вебе.
Мы стараемся применять анимации даже на самые рядовые действия — показ скрытых контролов на ховер, дроп-даун меню, информационные тултипы. Анимации помогают акцентировать внимание пользователя на элементы управления с помощью различных помигиваний и подёргиваний.
Плавное взаимодействие контролов и переходы из одного состояния в другое помогают пользователю лучше понять, что происходит со страницей. Не стоит ограничиваться на анимациях лишь в кнопочках и слайдерах, используйте своё воображение, всего пару CSS свойств позволит вам сделать ваш интерфейс намного приятней.
Обмен опытом
Подборка багов и решений
Натыкаясь на чужие примеры использования CSS3 анимаций и описание багов, мы часто списываем проблему на её специфичность и не обращаем внимания на проблему. Но даже если вы в ближайшее время не собираетесь делать ничего похожего, полезно заранее знать, с чем вам, возможно, придётся столкнуться — для этого мы подготовили небольшую подборку багов и решений, с которыми нам приходилось сталкиваться:
Демо страница на dabblet, архив с примерами (на Я.Диске).
Opera
При комбинировании анимаций, например, opacity с box-shadow, могут наблюдаться проблемы в Опере (см. блок 1 на демо странице), когда тень полностью исчезает вместе с ховером, при обратной анимации тень возвращается с задержкой и без ожидаемой плавности.
.no_sec {
transition: opacity 1s, box-shadow 0;
box-shadow: 0 0 5px 5px #000;
}
.no_sec:hover {opacity: 0; box-shadow: none;}
Чтобы избежать бага, нужно отдельно анимировать тень и пробовать подбирать другие значения скорости перехода.
.no_sec.shadow {
transition: opacity 1s, box-shadow .3s;
box-shadow: 0 0 5px 5px blue;
}
.no_sec.shadow:hover {opacity: 0; box-shadow: none;}
Блоки с псевдоэлементами проблемно анимируются в Opera 12, оставляя схожие артефакты с первым примером (блок 2), причем в Opera 11.64 работает стабильно.
.pseudo {
position: relative;
transition: opacity 1s;
}
.pseudo:hover {opacity: 0;}
.pseudo::after {
content: 'pseudo';
position: absolute;
left: 0; top: 100%;
height: 10px; width: 100%;
background: blue;
font-size: 10px; line-height: 1;
}
Приходится отказываться от псевдоэлементов и использовать обычные теги.
Firefox
Если не указать значение «s» (секунд) в transition, Firefox игнонирует анимацию полностью (блок 1). В блоке 3 выставлено рабочее значение анимации тени в Firefox.
Причем Firefox ведёт себя строго по документации, где указано, что значение времени должно определяться только мерой измерения, а другие браузеры выбрали более привычный подход для разработчиков.
Webkit
В Chrome на Mac (как минимум до 23-й версии) при использовании transition вместе с transform (блок 4), а также и при других условиях ломается сглаживание текста на всей странице.
Со сглаживанием:
Без сглаживания:
.scale {
transition: transform 1s;
/*-webkit-backface-
visibility: hidden;*/
}
.scale:hover {transform: scale(1.5)}
Проблему помогает решить свойство backface-visibility: hidden, применённый на body, либо на блок с мерцающим текстом, но такой фикс тоже имеет свои последствия (подробности ниже в статье), к тому же, текст потеряет сглаживание навсегда.
В Chrome не работает transition, если блок меняет свойства с display: block -> display: inline/inline-block (блок 5).
.inline b {opacity: 0; transition: opacity 1s; display: block; max-height: 0;}
.inline:hover b {opacity: 1; display: inline; }
Чтобы обойти проблему, нужно применять animation (блок 5.1).
@-webkit-keyframes reveal {
from { opacity: 0; }
to { opacity: 1; }
}
.inline.anim:hover b {-webkit-animation: reveal 1s;}
В Chrome на Windows во время плавной анимации transform все инпуты получают белый фон (блок 4 с трансформом и 6 с инпутом).
Подобный эффект также наблюдается, если на любой элемент страницы применить backface-visibility. Решение проблемы пока не было найдено.
Общие баги
Нигде, кроме Webkit, не работает transition на background-image, нельзя поставить даже задержку, картинка меняется мгновенно (блок 7).
.bg_img {
background: red url(image1.png);
transition: background-color 1s linear, background-image 0s linear 1s;
}
.bg_img:hover {background: blue url(image2.png);}
Для решения проблемы приходилось комбинировать анимацию в нескольких слоях с помощью opacity.
Во время transition блок с анимацией opacity перекрывает другие блоки.
Чтобы избежать проблем, нужно поставить блоки, на которые не нужна анимация ниже в доме (так они автоматически получат выше z-index), либо прописать z-index вручную (блок 8.1).
Обновляя страницу с примерами багов, через пару месяцев после первой версии выяснилось, что за это время ситуация никак не поменялась и за пару версий обновлений браузеров ни один из перечисленных багов по прежнему не починили.
На заметку
В CSS transition возможно контролировать анимацию в обе стороны, например, меняя скорость анимации:
.block {transition: 10s opacity;}
.block:hover {opacity: 0; transition-duration: 1s;}
При ховере переход в opacity: 0; произойдёт за 1 секунду, а обратный переход в opacity: 1; будет длиться 10 секунд. Таким образом, можно, например, при ховере “навсегда” оставить свойства ховер стейта, используя очень большую задержку.
При использовании animation, следует ожидать, что во время анимации блок не подвержен никаким внешним воздействиям (прим. смена цвета на ховер). Для этого можно сначала остановить анимацию, используя “animation-play-state:paused;“ или совсем обнулить анимацию, применяя свойство “animation: none;”.
Работая с анимациями, переодически приходится возвращаться к истокам и заново изучать самые древние возможности CSS, как у нас вышло с псевдоклассом :active.
Backface-visibility
Ранее мы упоминали backface-visibility как вариант решения некоторых багов webkit браузеров, но местами это свойство может привести к еще большим проблемам. Помимо стандартного предназначения этого свойства (прятать обратную сторону 3D анимируемого блока), его часто используют для включения аппаратного ускорения, позволяющего с помощью GPU ускорить время рендеринга страниц в браузере.
Применение этого свойства хоть на 1 элемент страницы может повлиять на всю страницу целиком, например, вызвав белый фон под всеми инпутами (7-й пункт подборки багов анимаций) или изменить режим сглаживания текста.
Недавно мы обнаружили, что, применяя это свойство динамически после того, как уже отрисована часть страницы, среднее время рендеринга страницы сильно увеличивается. Скорее всего это связано с переходом в режим GPU ускорения, при котором перерисовывается вся страница.
Первый раз мы столкнулись с последствиями этого свойства, когда решили применить его на элемент body для Chrome и Safari на Mac ради избежания мерцания текста при анимациях. При этом в Safari 5 стало появляться множество необъяснимых багов, страница разъезжалась в совершенно непредсказуемых местах, вследствие пришлось оставить backface-visibility только для Chrome Mac и на самые проблемные места с мерцающим текстом в Safari. С выходом Safari 6 ситуация немного устаканилась и поведение браузера по отношению к злополучному свойству приравнялось к поведению нынешнего Chrome.
На прицеле
Всегда следите за обновлениями браузеров и проверяйте свой портал на developer и preview версиях, если вы не хотите, чтобы ваш портал прогнулся под натиском багов из-за очередного обновления браузера.
Помимо реализации поддержки новых технологий и откидывания префиксов, вместе с новой версией могут прийти не совсем стабильные алгоритмы оптимизации рендеринга страницы. Учитывая, что часть рендеринга браузеры начинают перекидывать на GPU, стоит так же ожидать, что баги могут воспроизводится только на машинах с определённым железом. Были случаи, что на некоторых компьютерах в одном и том же браузере не работал 3D transform из-за видео карты.
Вместе с выходом 21-й версии Chrome на стабильной ветке нам пришлось встретится с кучей необъяснимых багов, касающихся не только CSS3 анимаций, одним из критичных оказался баг с черными пятнами (только в Chrome на Windows), которые хаотично появлялись по всей странице из-за анимации opacity. Самое интересное, что версии stable и dev (в Chrome) могут легко отличаться, даже если в 22-й dev версии баг починен, не факт, что с переводом ветки в stable фикс останется.
Интересный случай наблюдался и с выходом Safari 6, с обновлением браузер подтянул много изменений из ветки разработки webkit движка и перенял множество багов нынешнего Chrome.
Оптимизация
Одно из основных правил нашей команды разработки интерфейсов — как можно больше pure CSS решений. Использование CSS взамен JavaScript даёт отличный прирост производительности клиентской части как и по скорости работы интерфейса, так и по времени разработки.
Every byte counts
Используйте короткие сокращенные нотации вместо перечисления каждого свойства отдельно.
transition-property: top;
transition-duration: 1s;
transition-timing-function: ease;
transition-delay: 0.5s;
=transition: top 1s .5s;
К слову, самая минимальная запись анимации — “transition: 1s”, остальные свойства по умолчанию: «all ease 0;»
Часто приходится встречать примеры не рационального использования анимаций, когда вместо того, чтобы определить конкретные, анимируемые свойства, разработчики используют
transition: all … ;
взамен четкого
transition: opacity … ;
Возможно, это поможет вам сэкономить пару символов, но в итоге вы в разы больше нагрузите браузер лишними вычислениями при изменении несколько параметров анимируемого блока.
Также не забывайте следить за префиксами, например, свойств -ms-animation и -ms-transition вообще не существует, т.к. 10-ая версия Internet Explorer вышла с уже опущенными префиксами. CSS препроцессоры позволяют сильно упросить работу с префиксами с помощью миксинов.
Стандартизируем
Подход объектно ориентированного CSS позволяет хорошо сэкономить на повторяющихся свойствах. Мы активно используем OOCSS подход в нашей системе организации стилей, что также касается стандартизации анимаций.
Вот пример одного из переиспользуемых модулей:
.fade {
transition: .3s opacity, visibility 0s .3s;
visibility:hidden;
opacity: 0;
}
.fade_in:hover .fade {
transition-delay: 0s;
visibility: visible;
opacity: 1;
}
Этот стандартный модуль позволяет нам сэкономить кучу повторных вхождений кода для самого часто встречающегося эффекта анимации. Используя дополнительно свойство “visibility”, мы реализуем обратную совместимость для браузеров, не поддерживающих CSS анимации.
Вывод
Глядя на множество трудностей, с которыми приходится сталкиваться при работе с CSS анимациями, может показаться, что усилия не оправданы, но это совершенно не так:
Во-первых, мы открыли для себя мощный инструмент улучшения взаимодействия интерфейса с пользователем, не сильно влияющий на клиентскую производительность в сравнении с JavaScript аналогами. Нативность технологии позволяет браузерам лучше оптимизировать скорость отрисовки элементов также за счет использования вычислительных мощностей GPU.
Во-вторых, мы очень довольны гибкостью CSS анимаций, скоростью и простотой внедрения технологии в существующие и новые интерфейсы. Разработав общие подходы и разобравшись с особенностями технологии один раз, мы с лёгкостью можем её применять на множестве внутренних проектов.
В-третьих, работать с CSS анимациями интересно! Что может быть более вдохновляющим, чем быть пионерами технологии и прокладывать первые пути? Если в задаче по созданию нового интерфейса есть хоть один анимируемый элемент, то работать с ней становится намного захватывающе. Особенно приятно слышать похвальные отзывы, делясь наработками с коллегами-верстальщиками.