В последнее время в Техасе холодно и снежно. Это вдохновило меня на создание анимации с падающим снегом. Делается это быстро, все вместе занимает от силы 10 минут.
Примечание. Я буду использовать Pug и Sass/SCSS для упрощения повторяющихся частей HTML и CSS соответственно. Но это не обязательно. Вы можете экстраполировать код и сделать все на чистых HTML и CSS.
Вот как наша анимация будет выглядеть:
See the Pen Snowfall animation by Alvaro Montoro (@alvaromontoro) on CodePen.
Создаем фон
Давайте начнем с фона. Этот шаг опционален, его можно сделать по-разному. Для целей этой статьи мы ограничимся просто темным фоном со следующим CSS:
html, body { padding: 0; margin: 0; width: 100vw; height: 100vh; position: relative; overflow: hidden; background: linear-gradient(#123, #111); }
Добавляем снежинки
Затем мы создаем блок <div>
для каждой снежинки, которая будет у нас на экране. Мы можем сделать что-то типа такого:
<div class="snowflake"></div> ... ... ... <div class="snowflake"></div> <div class="snowflake"></div> <!-- 50 раз! -->
Но для простоты лучше применим PugJS. Он позволяет использовать циклы для повторяющихся задач:
- for (i = 0; i < 50; i++) div(class="snowflake")
Стилизация снежинок
Теперь у нас есть блоки <div>
для всех снежинок на странице. Осталось их стилизовать. Снежинки будут маленькими, круглыми и белыми:
.snowflake { --size: 1vw; width: var(--size); height: var(--size); background: white; border-radius: 50%; position: absolute; top: -5vh; }
Мы использовали пользовательское свойство (--size)
для ширины и высоты. Благодаря этому позже сможем без проблем получить снежинки разных размеров.
Также мы позиционировали снежинки вне области видимости (сверху). Падать они будут в зону, также находящуюся вне области видимости (снизу).
Анимация
Чтобы анимировать снегопад, мы используем CSS-анимацию с @keyframes
. Начнем с чего-то простого, а затем немного усложним.
Для начала мы применим translate3d
, чтобы заставить снежинки двигаться вертикально. Поскольку это 3D-преобразование, оно будет триггерить ускорение железа и выглядеть красивее, чем если бы мы анимировали другое свойство, например top
:
@keyframes snowfall { 0% { transform: translate3d(0, 0, 0); } 100% { transform: translate3d(0, 110vh, 0); } }
Мы могли бы применить эту анимацию для класса snowflake
, добавив следующее свойство:
animation: snowfall 5s linear infinite;
Но тогда снежинки двигались бы только вертикально сверху вниз. Это выглядело бы не слишком натурально. Плюс, все снежинки перекрывают друг друга из-за абсолютного позиционирования, что не очень хорошо смотрится. Нам надо это исправить.
Мы могли бы создать 50 разных правил, по одному для каждой снежинки, назначив для каждой разные позиции left, углы и скорости. Но, хотя сделать это на чистом CSS вполне реально, это все же куча работы:
.snowflake:nth-child(1) { --size: 0.6vw; left: 55vw; animation: snowfall 8s linear infinite; } ... .snowflake:nth-child(49) { --size: 1vw; left: 78vw; animation: snowfall 7s linear infinite; } .snowflake:nth-child(50) { --size: 1.5vw; left: 20vw; animation: snowfall 10s linear infinite; }
Проще написать код с помощью SCSS и его функций, а затем использовать сгенерированный CSS-код. Поэтому, вместо того чтобы писать сотни строк кода, мы можем использовать циклы и существенно упростить разработку:
@for $i from 1 through 50 { .snowflake:nth-child(#{$i}) { --size: #{random(5) * 0.2}vw; /* randomize size! */ left: #{random(100)}vw; animation: snowfall #{5 + random(10)}s linear infinite; } }
Бац! Всего 7 строк кода, которые позже скомпилируются в 250! И нам не нужно придумывать рандомные числа, поскольку в SCSS для этого есть специальная функция random().
Последние штрихи
Все наши снежинки разных размеров и перемещаются с разной скоростью, но они все еще двигаются просто по вертикали, а это неприродно. Для добавления рандомных движений в стороны мы можем скомбинировать CSS-переменные и SCSS-функции:
/* uses CSS variables to determine initial and final position */ @keyframes snowfall { 0% { transform: translate3d(var(--left-ini), 0, 0); } 100% { transform: translate3d(var(--left-end), 110vh, 0); } } @for $i from 1 through 50 { .snowflake:nth-child(#{$i}) { --size: #{random(5) * 0.2}vw; --left-ini: #{random(20) - 10}vw; /* random initial translation */ --left-end: #{random(20) - 10}vw; /* random final translation */ left: #{random(100)}vw; animation: snowfall #{5 + random(10)}s linear infinite; animation-delay: -#{random(10)}s; } }
Наконец, мы добавляем отрицательную задержку animation-delay
, чтобы не все снежинки стартовали одновременно. В противном случае все они начали бы свое падение в один момент, что выглядело бы странно.
Апдейт: переместим переменные в HTML
Код, приведенный выше, нормальный. Но он генерирует слишком много повторяющихся с небольшими отличиями CSS-правил. Мы их можем упростить, сведя к одному свойству (или к двум) прямо в классе .snowflake
, и использовать CSS-переменные для каждого элемента.
Идея в том, чтобы перенести объявление CSS-переменных из CSS в HTML:
<!-- 1 --> <div class="snowflake" style="--left: 69vw; --left-ini: -4vw; --left-end: 0vw; --speed: 8s; --size: 0.4vw; --delay: -10s;"></div> ... ... ... <!-- 50 --> <div class="snowflake" style="--left: 83vw; --left-ini: 5vw; --left-end: 1vw; --speed: 10s; --size: 0
Нам нужно определить функцию random в PugJS, а затем использовать ее для установки значений CSS-переменных:
- function random(num) { return Math.floor(Math.random() * num) } - for (i = 0; i < 50; i++) div(class="snowflake", style=`--left: ${random(100)}vw; --left-ini: ${random(20) - 10}vw; --left-end: ${random(20) - 10}vw; --speed: ${5 + random(15)}s; --size: ${random(5) * 0.2}vw; --delay: -${random(15)}s;`)
Теперь, когда все эти значения есть в HTML, мы можем удалить все CSS-селекторы и поместить свойства анимации прямо в определении .snowflake
:
.snowflake { width: var(--size); height: var(--size); background: white; border-radius: 50%; position: absolute; top: -5vh; left: var(--left); animation: snowfall var(--speed) linear infinite; animation-delay: var(--delay); }
Это решение делает CSS-код существенно меньше и проще (из 500 строк остаются 34!), хотя и привносит немного сложности в HTML.
Итоги
Падающий снег — простая, но привлекающая внимание анимация. Вместе с тем она может быть довольно ресурсоемкой, если снежинок будет очень много. Будьте осторожны.
Видео создания анимации можно посмотреть на YouTube:
Перевод статьи «Creating a snowfall effect with HTML and CSS».
[customscript]techrocks_custom_after_post_html[/customscript]
[customscript]techrocks_custom_script[/customscript]