Анимация без стереотипов
Хоть анимация и понимается прежде всего как «оживление», в CSS кроме обычной плавной анимации, есть ещё пара типов — дискретная и никакая (свойство не анимируется).
Про неанимируемые свойства понятно из названия. А что за дискретная анимация? В отличие от плавной анимации, когда одно значение может быть интерполировано, суммировано или аккумулировано к другому, в дискретном варианте значение сменяется, но без плавности, а просто в середине кейфрейма становится другим.
Свойства с плавной анимацией — это цвета, размеры, отступы и прочие свойства, к которым можно применить плавные переходы.
Свойства с дискретнной анимацией — (внезапно) почти все остальные свойства, за некоторым исключением.
Ок, как это можно использовать. В этом кейсе я воспринимаю анимацию как механизм переключения значения свойства из одного в другое (с опциональным таймером и повторением N-раз). То есть некий setInterval(() => fn(value)), только в мире CSS.
Я полистал список всех CSS-свойств и выбрал несколько, об анимации которых я раньше не задумывался. Например, свойство content. Можно сделать «мигающий курсор»:
div::after { animation: blink 1s infinite;}
@keyframes blink { from { content: ""; } to { content: "|"; }}А учитывая, что content в качестве значения поддерживает текст, картинки, кавычки, счётчики, то можно сделать хоть целое слайдшоу 😁
Окей, ещё с помощью дискретной анимации можно собрать свою gif-ку на коленке. Это буквально быстрая смена «кадров» с картинками, как в кино. Если в секунду сменять 10 «кадров», то скорость будет достаточная для создания иллюзии непрерывного движения:
.frame { animation: movie 1s infinite;}
@keyframes movie { 0% { background-image: var(--image-1); }
10% { background-image: var(--image-2); }
…}Демо собрано тут.
Дальше я решил развить тему кинематографа и следующим попробовать анимировать лейаут гридов. Для построения отдельных «кадров» я решил использовать свойство grid-template-areas. Это свойство описывает раскладку грида в декларативном виде. Вот так, к примеру, будет выглядеть начальный «кадр» будущего фильма:
grid-template-areas: ". . . . a a a a a . . . ." ". . . . . . . . b . . . ." ". . . . . . . . b . . . ." ". . . . . . . . b . . . ." ". . . . c c c c c . . . ." ". . . . . . . . d . . . ." ". . . . . . . . d . . . ." ". . . . . . . . d . . . ." ". . . . . . . . d . . . ." ". . . . e e e e e . . . .";Точками в значении grid-template-areas обозначены те области грида, которые не будут закрашены белым, а буквами — те, которые закрашиваются. По ходу «фильма» значение grid-template-areas будет принимать разные значения. А вот подменять эти значения раскладки грида будет CSS-анимация. Для этого нужно прописать раскадровку «фильма» в кейфреймах:
@keyframes movie { 0% { grid-template-areas: …; } 10% { grid-template-areas: …; }
… 100% { grid-template-areas: …; }}И затем задать получившуюся анимацию для грид-контейнера .field:
.field { animation-name: movie; animation-duration: 10s; animation-play-state: paused; animation-timing-function: step-end; animation-iteration-count: 1; animation-fill-mode: both;}Получившийся триллер можно найти тут.
И ещё одна деталь про неанимируемые свойства. А что будет, если в кейфреймы положить display: none? Оно применится в конце, начале или середине анимации?
.fade-out { animation: fade-out 1s forwards;}
@keyframes fade-out { 100% { opacity: 0; display: none; }}Спецификация говорит, что свойство display — not animatable. И для display: none с относительно недавних пор действует особое правило: если анимация «появляет» элемент, то display включается в самом начале, а если анимация элемент скрывает, то display: none применяется в самом конце, после всех остальных транзишнов (демо тут, работает везде)!