Как сделать таймер на CSS
@property
, @keyframes
, и псевдоэлементы со значениями counter()
.Иногда, на сайтах используется таймер.
Возможно, необходимо засечь время проведения викторины или задать время проведения опроса. А может, просто хотим сделать эффектный обратный отсчёт после того, как пользователь совершил что-то грандиозное, например, успешно забронировал билет на концерт. Возможно, нужно создать инструмент для микротайм-менеджмента (вспомните Pomodoro). Или это может быть просто альтернатива UI со спиннером.
Когда возникают такие ситуации, на помощь приходит JavaScript, который, вероятно, является более мощным инструментом для решения подобных задач. И всё же! Использование CSS-заменителей так же интересно и эффективно, когда самый простой вариант является лучшим. В наши дни некоторые почтовые клиенты обладают большими возможностями CSS, но не используют JavaScript, так что, возможно, эта ситуация может стать интересным прогрессивным усовершенствованием.
Давайте посмотрим, что нужно для создания CSS таймера. Используем для этого некоторые современные CSS-технологии. Ингредиенты?
- CSS счётчики
@property
- псевдоэлементы
@keyframes
- Немного кельтской морской соли по вкусу
Чтобы начать, запустите (Code)Pen и держите его разогретым. Далее приведена демонстрация, над которой будем работать (позже приведу несколько стилизованных примеров):
К CSS таймеру предъявляются три основных требования:
- Число, которое может уменьшаться от 5 до 0.
- Способ засечь пять секунд и уменьшать число в каждой из них.
- Способ отображения уменьшающегося числа на странице.
Число
Для первого требования — обновляемого числа — воспользуемся @property
, чтобы создать свойство, содержащее значение типа <integer>
.
Примечание: Целое число может быть нулём, положительным или отрицательным целым числом. Если нужны числа с десятичными значениями, используйте <number>
, хранящий вещественное число.
@property --n {
syntax: "<integer>";
inherits: false;
initial-value: 0;
}
Отсчёт
Для отслеживания секунд, при уменьшении их количества, перейдём к @keyframes
анимации.
@keyframes count {
from { --n: 5; }
to { --n: 0; }
}
Функция анимации запускается в действие с помощью свойства animation
.
.timer:hover::after {
animation: 5s linear count;
}
Вот что происходит:
При регистрации пользовательского свойства для определённого типа значения, например <integer>
, <percentage>
или <color>
, браузер понимает, что свойство создано для работы с этим конкретным типом значения.
Зная это, браузер уверенно обновляет значение пользовательского свойства в будущем, даже во время анимации.
Вот почему свойство --n
может изменяться от 5 до 0 во время анимации, а так как анимация задана в пять секунд, то, по сути, это отсчёт от 5 до 0 за пять секунд. Таким образом, рождается таймер.
Но ещё предстоит вывести отсчитанные числа на страницу. Если вы не заметили, ранее анимация была назначена псевдоэлементу, и это должно дать подсказку для следующего шага — content
.
Отображение
Свойство content
может отображать содержимое, которое ещё не добавлено в HTML. Обычно это свойство используется для разных целей, потому что оно принимает различные значения — изображения, строки, счётчики, кавычки, даже значения атрибутов. Однако оно не принимает непосредственно число. Поэтому передадим ему число --n
через counter.
Счётчик можно установить либо с помощью counter-reset
, либо с помощью counter-increment
. Будем использовать counter-reset
. Значение этого свойства — имя счётчика и целое число. Поскольку counter-reset
ещё не умеет корректно обрабатывать CSS переменные или пользовательские свойства для целого числа, но принимает calc()
, функция calc()
становится троянским конём, внутрь которого отправим --n
.
.timer:hover::after {
animation: 5s linear count;
animation-fill-mode: forwards;
counter-reset: n calc(0 + var(--n));
content: counter(n);
}
Это:
- Наше анимируемое число
--n
сначала передаётся вcalc()
. - Затем
calc()
передаётся вcounter()
. counter()
, в свою очередь, передаётся вcontent
, что в итоге выводит--n
на страницу.
Об остальном позаботится браузер. Он знает, что --n
— целое число. Браузер следит за анимацией, изменяющей это целое число с 5 до 0 за пять секунд. Затем, поскольку целое число используется в значении content
, браузер отображает целое число на странице по мере его обновления.
В конце анимации правило стиля animation-fill-mode: forwards
; не позволяет таймеру сразу вернуться к начальному значению --n
.
И снова перед вами финальная версия:
В качестве вариантов оформления можно вести счёт по возрастающей или убывающей, играть с его внешним видом или комбинировать с другими типичными дизайнами загрузчика или прогресса, например, с круговой анимацией.
На момент написания статьи Firefox является единственным браузером, не поддерживающим @property
, но они объявили о намерении выпустить его, так что ждать осталось недолго. Для получения справки о поддержке, вот страница caniuse.com для @property
.
Пользовательские свойства CSS также можно устанавливать и обновлять в JavaScript. Поэтому, если в какой-то момент вы захотите обновить свойство в JavaScript, как и любое другое CSS свойство, это можно сделать с помощью функции setProperty()
. А если захотите создать новое пользовательское свойство в JavaScript, это можно сделать с помощью функции registerProperty()
. С другой стороны, если вы хотите сообщить JavaScript о завершении CSS-анимации, можно прослушивать событие animationend
.
Если вы увлекаетесь подобными вещами, ознакомьтесь с недавней статьёй Yuan Chuan Time-based CSS Animations
.