От автора: на днях я столкнулся с интересной проблемой. Я хотел анимировать элемент со случайным значением animation-duration. Начал я с обычной версии.
CSS код анимации:
1 2 3 4 5 6 7 8 9 10 11 12 |
@keyframes flicker { 0% { opacity: 1; } 100% { opacity: 0; } } #red { animation: flicker 2s ease alternate infinite; } |
В принципе, все хорошо работает. Но данный способ не рандомизированный, здесь заданы фиксированные 2 секунды. Я хотел сделать так, чтобы длительность анимации была произвольной. По сути, я хотел написать так:
1 2 3 |
.element { animation: flicker $randomNumber alternate infinite; } |
Где $randomNumber случайное значение, вычисленное программно. В CSS препроцессорах типа Sass есть функция random().
1 2 3 4 5 |
$randomNumber: random(5); .thing { animation-duration: $randomNumber + s; } |
Для вас, может быть, функция нормальная, однако не для меня. У этой функции есть большой недостаток. Другими словами, как только обрабатывается CSS, рандомизация заканчивается. Число ограничено этим значением навечно (т.е. пока заново не будет запущен препроцессор).
Здесь принцип не как в генерации через JS (Math.random()), где случайное число генерируется при запуске JS.
После громчайшего вздоха я понял, что это замечательная возможность воспользоваться родными CSS переменными (пользовательскими свойствами)! Сами по себе переменные не упростят генерацию случайных чисел, однако они могут помочь нам, и мы в этом убедимся.
Если вы не слышали про CSS переменные, не пугайтесь. По факту, это родные переменные, встроенные в CSS, однако они отличаются от тех переменных, которые вы знаете в препроцессорах типа Sass и Less. Крис привел много преимуществ:
их можно использовать без препроцессора;
они каскадируются. Чтобы переписать текущее значение или задать его, можно создать переменную внутри любого селектора;
при изменении значения (например, через медиа запросы или другие состояния), браузер перерисовывает элемент;
CSS переменными можно манипулировать через JS.
Нам очень важен последний пункт. Мы будем генерировать случайное число в JS и перемещать его в CSS с помощью пользовательских свойств.
Задайте CSS переменную со значением по умолчанию (удобно, если JS внезапно не сработает):
1 2 3 4 |
/* время перехода по умолчанию */ :root { --animation-time: 2s; } |
Теперь эту переменную можно использовать в нашем CSS:
1 2 3 |
#red { animation: flicker var(--animation-time) ease alternate infinite; } |
Мы пришли ровно к тому, с чего начали. Это демо визуально ничем не отличается от предыдущего, однако в этот раз в SVG анимации используются CSS переменные. Проверить, что все работает, можно, изменив значение переменной в CSS. Анимация должна обновиться.
Все готово для поиска и манипулирования пользовательским свойством через JS.
1 |
var time = Math.random(); |
Отсюда мы можем найти красный круг в SVG и изменить CSS переменную —animation-time с помощью метода setProperty:
1 2 |
var red = document.querySelector('#red'); red.style.setProperty('--animation-time', time +'s'); |
И вот и все! Случайно сгенерированное число в CSS, используемое в SVG анимации:
Уже лучше, случайное число генерируется при запуске JS, поэтому оно всегда разное. Это почти то, что мы хотели, но давайте еще немного усложним задачу: будем периодически рандомизировать animation-duration во время работы.
К счастью, мы работаем с JS, мы можем обновлять пользовательское свойство, когда захотим. Пример с обновлением animation-duration каждую секунду:
1 2 3 4 5 6 7 8 9 10 11 12 |
var red = document.querySelector('#red'); function setProperty(duration) { red.style.setProperty('--animation-time', duration +'s'); } function changeAnimationTime() { var animationDuration = Math.random(); setProperty(animationDuration); } setInterval(changeAnimationTime, 1000); |
Именно этого я и хотел добиться:
Важно знать, что поддержка CSS переменных (пользовательских свойств) все еще неоднородна. К этой анимации можно было применить технику прогрессивного улучшения:
1 2 3 4 |
#red { animation: flicker .5s ease alternate infinite; animation: flicker var(--animation-time) ease alternate infinite; } |
Если поддержка CSS переменных отсутствует, мы увидим хоть какую-то анимацию, пусть и не точно такую же.
Нужно сказать, что рандомизировать animation-duration можно не только с помощью CSS переменных. Можно также получать DOM элемент через JS и напрямую вставлять случайное значение в style:
1 2 |
var red = document.querySelector('#red'); red.style.animationDuration = Math.floor(Math.random() * 5 + 1) + "s"; |
Можно даже ждать, когда закончится анимация, и задавать новое значение продолжительности:
1 2 3 4 5 6 7 |
var red = document.querySelector('#red'); function setRandomAnimationDuration() { red.style.animationDuration = Math.floor(Math.random() * 10 + 1) + "s"; } red.addEventListener("animationiteration", setRandomAnimationDuration); |
Покажу еще один способ. Можно генерировать случайные числа с помощью EQCSS.
1 2 3 4 5 |
@element '#animation' { .element { animation-duration: eval('rand')s; } } |
1 2 |
var rand = Math.random(); EQCSS.apply(); |
А вы хотите, чтобы генерация случайных чисел была доступна прямо в CSS? Не уверен, что на эту тему ведутся хоть какие-то обсуждения. Даже если они и были, нам придется подождать, прежде чем использовать метод. Филипп Уолтон недавно писал о том, как сложно написать хороший полифил для генерации случайных чисел в CSS. Намного проще это делать в JS!
Автор: Robin Rendle
Источник: //css-tricks.com/
Редакция: Команда webformyself.
Комментарии (1)