От автора: в этом уроке я расскажу про мой любимый трюк в CSS переходах — Last In, First Out.
Введение
В приложениях и на современных веб-сайтах интерактивность и UX играют огромную роль в удержании пользователей. CSS анимация открыла перед нами возможность улучшения пользовательского опыта, но если немного подумать, то можно зайти еще дальше. В этом уроке мы напишем анимацию, которую я люблю называть «last in, first out» или по-другому стек анимацию. Это значит, что при срабатывании какого-либо переключателя элементы начинают двигаться в определенной последовательности. При повторной активации переключателя элементы двигаются в обратном порядке (относительно первой анимации). Я покажу, как сделать данный трюк при помощи простых DIV’ов, но тут важна сама реализация.
Визуальное представление
Чтобы точнее понять, чего мы хотим достичь, давайте разберем весь процесс по изображениям. В нейтральном или базовом положении все наши дивы – назовем их строки – занимают фиксированное пространство. Ниже картинка:
Представьте, что мы нажали на какой-либо переключатель, и теперь нам необходимо, чтобы наши строки постепенно расширялись до 100%. Ниже визуальное представление этого момента:
После завершения анимации все строки должны занимать всю ширину контейнера:
Теперь при повторном нажатии на переключатель наши строки должны двигаться в обратном направлении. Нижняя строка завершает анимацию самой последней, но в обратном направлении начинает движение первой. Картинка:
В конце все строки должны вернуться в исходное положение, как показано на скриншоте ниже:
Создаем демо
Давайте создадим демо. Разметка довольно простая, состоит из элемента c-bars и его дочерних элементов c-bars__bar. Также у нас есть переключатель, который будет добавлять всем строкам класс is-expanded. Ниже HTML код:
1 2 3 4 5 6 7 8 9 |
<button class="c-btn">Toggle</button> <div class="c-bars"> <span class="c-bars__bar">1</span> <span class="c-bars__bar">2</span> <span class="c-bars__bar">3</span> <span class="c-bars__bar">4</span> <span class="c-bars__bar">5</span> </div> |
JavaScript код для добавления класса очень простой:
1 2 3 4 5 6 7 8 9 10 |
<script> var btn = document.querySelector('.c-btn'); var bars = document.querySelectorAll('.c-bars__bar'); btn.addEventListener('click', function() { for (var i = 0; i < bars.length; i++) { bars[i].classList.toggle('is-expanded'); } }); </script> |
В реальном примере скрипт может сильно отличаться. В нашем случае суть в том, что при нажатии кнопки ко всем строкам должен добавляться класс is-expanded.
Базовые стили
После разметка необходимо добавить стили. У нашего контейнера будет рамка, а строки будут блочными элементами с изначальной шириной. Ширина строк задается для того, чтобы мы могли задавать свойство transition от определенной ширины до 100%. Ниже CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.c-bars { padding: 12px; border: solid 4px #25b7a8; } .c-bars__bar { display: block; margin: 0 0 12px 0; padding: 2px 0; width: 24px; color: #fff; background-color: #25b7a8; text-align: center; transition: width 0.5s; } .c-bars__bar:last-child { margin-bottom: 0; } |
Как сказано выше, класс is-expanded добавляется при нажатии на кнопку. Т.е. именно здесь необходимо задать другое значение ширины для строк:
1 2 3 |
.c-bars__bar.is-expanded { width: 100%; } |
На данном этапе по клику на кнопку сработает анимация, и ширина всех строк будет плавно изменяться от изначальной ширины до 100%. Повторный клик вернет строки в изначальное положение.
Трюк 1 – Последовательные переходы
Сейчас все элементы, как при увеличении ширины, так и при уменьшении ширины двигаются одновременно. Чтобы сделать анимацию последовательной, необходимо задать свойство transition-delay. Известно, что у нас 5 строк. Зададим при помощи nth-child каждой строке задержку в 0.1s. CSS код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.c-bars__bar:nth-child(1) { transition-delay: 0s; } .c-bars__bar:nth-child(2) { transition-delay: 0.1s; } .c-bars__bar:nth-child(3) { transition-delay: 0.2s; } .c-bars__bar:nth-child(4) { transition-delay: 0.3s; } .c-bars__bar:nth-child(5) { transition-delay: 0.4s; } |
Если нажать на кнопку сейчас, то первая строка начинает двигаться сразу же, а каждая следующая с задержкой в 0.1s от предыдущей. Отличный эффект! Но если нажать на кнопку еще раз, то вы заметите, что обратная анимация идет в том же порядке, что и обычная. Не совсем то, что мы хотим. Давайте взглянем на второй трюк.
Трюк 2 — Last In, First Out
Чтобы добиться эффекта анимации last in, first out, необходимо рассмотреть два состояния строк в демо. Первое состояние – изначальное, второе – расширенное. Мы уже знаем, как создать последовательную анимацию от изначального состояния к расширенному. Когда все строки находятся в расширенном состоянии необходимо инвертировать значения transition-delay для каждой строки. К счастью, сделать это довольно просто.
При клике на кнопку к элементам моментально добавляется класс is-expanded. Это значит, что во время анимации расширения данный класс присутствует в каждой строке. При повторном клике на кнопку данный класс немедленно удаляется. Т.е. мы можем работать с двумя фазами:
Задержка анимации от изначального к расширенному состоянию применяется к классу is-expanded.
А задержка от расширенного к изначальному состоянию применяется к базовому классу.
Модифицированный CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
.c-bars__bar:nth-child(1) { transition-delay: 0.4s; } .c-bars__bar.is-expanded:nth-child(1) { transition-delay: 0s; } .c-bars__bar:nth-child(2) { transition-delay: 0.3s; } .c-bars__bar.is-expanded:nth-child(2) { transition-delay: 0.1s; } .c-bars__bar:nth-child(3) { transition-delay: 0.2s; } .c-bars__bar.is-expanded:nth-child(3) { transition-delay: 0.2s; } .c-bars__bar:nth-child(4) { transition-delay: 0.1s; } .c-bars__bar.is-expanded:nth-child(4) { transition-delay: 0.3s; } .c-bars__bar:nth-child(5) { transition-delay: 0s; } .c-bars__bar.is-expanded:nth-child(5) { transition-delay: 0.4s; } |
Проверьте анимацию теперь. Вы успешно реализовали технику last in, first out, и она смотрится превосходно.
Упрощение при помощи Sass
В основе этого эффекта анимации лежит фундаментальная математическая основа, а значит, тут нам может помочь Sass (или любой препроцессор CSS с циклами и переменными). Блок Sass, заменяющий написанный выше CSS код, очень прост:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$n: 5; $delay: 0.1; @for $i from 1 through $n { $in: $delay * ($i - 1); $out: $delay * ($n - $i); .c-bars__bar:nth-child(#{$i}) { transition-delay: #{$out}s; } .c-bars__bar.is-expanded:nth-child(#{$i}) { transition-delay: #{$in}s; } } |
Изменяя значения $n (количество строк) и $delay (задержка анимации), можно полностью менять анимацию
Заключение
Пора подводить итоги! Только что мы разобрали простой, но удивительный CSS пример по созданию последовательной стек анимации. Количество способов применения данной техники бесконечно. Если вы хотите посмотреть мои примеры, то перейдите на CSS Circle Menu.