Как сделать таймер на CSS

Источник: «How to Make a CSS Timer»
Давайте рассмотрим использование CSS в качестве альтернативы JavaScript для создания простых таймеров. Используем современные свойства CSS, такие, как @property, @keyframes, и псевдоэлементы со значениями counter().

Иногда, на сайтах используется таймер.

Возможно, необходимо засечь время проведения викторины или задать время проведения опроса. А может, просто хотим сделать эффектный обратный отсчёт после того, как пользователь совершил что-то грандиозное, например, успешно забронировал билет на концерт. Возможно, нужно создать инструмент для микротайм-менеджмента (вспомните Pomodoro). Или это может быть просто альтернатива UI со спиннером.

Когда возникают такие ситуации, на помощь приходит JavaScript, который, вероятно, является более мощным инструментом для решения подобных задач. И всё же! Использование CSS-заменителей так же интересно и эффективно, когда самый простой вариант является лучшим. В наши дни некоторые почтовые клиенты обладают большими возможностями CSS, но не используют JavaScript, так что, возможно, эта ситуация может стать интересным прогрессивным усовершенствованием.

Давайте посмотрим, что нужно для создания CSS таймера. Используем для этого некоторые современные CSS-технологии. Ингредиенты?

Чтобы начать, запустите (Code)Pen и держите его разогретым. Далее приведена демонстрация, над которой будем работать (позже приведу несколько стилизованных примеров):

See the Pen

К CSS таймеру предъявляются три основных требования:

  1. Число, которое может уменьшаться от 5 до 0.
  2. Способ засечь пять секунд и уменьшать число в каждой из них.
  3. Способ отображения уменьшающегося числа на странице.

Число

Для первого требования — обновляемого числа — воспользуемся @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);
}

Это:

  1. Наше анимируемое число --n сначала передаётся в calc().
  2. Затем calc() передаётся в counter().
  3. counter(), в свою очередь, передаётся в content, что в итоге выводит --n на страницу.

Об остальном позаботится браузер. Он знает, что --n — целое число. Браузер следит за анимацией, изменяющей это целое число с 5 до 0 за пять секунд. Затем, поскольку целое число используется в значении content, браузер отображает целое число на странице по мере его обновления.

В конце анимации правило стиля animation-fill-mode: forwards; не позволяет таймеру сразу вернуться к начальному значению --n.

И снова перед вами финальная версия:

See the Pen

В качестве вариантов оформления можно вести счёт по возрастающей или убывающей, играть с его внешним видом или комбинировать с другими типичными дизайнами загрузчика или прогресса, например, с круговой анимацией.

See the Pen


See the Pen

На момент написания статьи Firefox является единственным браузером, не поддерживающим @property, но они объявили о намерении выпустить его, так что ждать осталось недолго. Для получения справки о поддержке, вот страница caniuse.com для @property.

Пользовательские свойства CSS также можно устанавливать и обновлять в JavaScript. Поэтому, если в какой-то момент вы захотите обновить свойство в JavaScript, как и любое другое CSS свойство, это можно сделать с помощью функции setProperty(). А если захотите создать новое пользовательское свойство в JavaScript, это можно сделать с помощью функции registerProperty(). С другой стороны, если вы хотите сообщить JavaScript о завершении CSS-анимации, можно прослушивать событие animationend.

Если вы увлекаетесь подобными вещами, ознакомьтесь с недавней статьёй Yuan Chuan Time-based CSS Animations.

Дополнительные материалы

Предыдущая Статья

Управляйте промисами используя Promise.withResolvers()

Следующая Статья

PHP 8.4: Вызов session_set_save_handler() с более чем 2 аргументами объявлен устаревшим