Анимированный индикатор прогресса в стиле Material Design

9a68d95547a6ee89a91ba53556cb3cc8ed294141
Расскажу, как можно создать анимированный индикатор прогресса в стиле Material Design с использованием CSS и SVG.

Индикаторы выполнения или индикаторы загрузки используются для обозначения длительных процессов, статусов или состояния приложения. Например, при отправке формы, или ожидании загрузки чего-либо на странице. Они информируют пользователя о том, что в данный момент происходит какое-то действие, требующее ожидание его окончания. Такие индикаторы могут быть с определённым временем ожидания, когда вы знаете сколько времени займет операция, так и с неопределённым. Последние обычно представляют собой индикаторы с зацикленной анимацией.

Здесь я покажу как сверстать такой индикатор с неопределенным временем ожидания.

HTML-разметка

Начнём с рисования простого круга с помощью SVG:

<div class="loader">
    <svg class="loader__svg" viewBox="0 0 50 50">
        <circle class="loader__path" cx="25" cy="25" r="25"></circle>
    </svg>
</div>

Теперь превратим круг в окружность. Для этого уберем заливку и добавим обводку в SVG

.loader__path {
  fill: none;
  stroke: black;
  stroke-width: 4;
  stroke-linecap: round;
}

Однако мы сразу же столкнемся с проблемой: обводка будет обрезана границами области просмотра SVG.

Для ее решения было бы проще всего нарисовать обводку внутри указанного радиуса. Примерно как inset в свойстве box-shadow. К сожалению, в SVG нет свойств для управления расположением обводки. Существуют варианты с использованием масок, однако они предполагают размещения дополнительного кода в SVG. Мне же хочется оставить разметку максимально простой. Поэтому предлагаю воспользоваться css-функцией calc() и пользовательскими css-свойствами, для указания толщины обводки и расчёта на её основе необходимого радиуса.

Чтобы уместить окружность в нужных границах нужно вычесть из половины ширины вьюбокса svg половину ширины обводки и установить это значение в качестве радиуса обводки. Обновим стили:

.loader {
  --loader-stroke-width: 4;
  --loader-stroke-color: #24ABDF;
}
.loader__path {
  fill: none;
  r: calc((50 - var(--loader-stroke-width)) / 2);
  stroke: var(--loader-stroke-color);
  stroke-width: var(--loader-stroke-width);
  stroke-linecap: round;
}

Анимация окружности

Пришло время анимировать обводку для получения эффекта в стиле Metarial Design. Воспользуемся свойствами stroke-dasharray и stroke-dashoffset для управления длиной штриха. Анимация будет начнаться с небольшой дуги и до почти полной окружности, и повторяться бесконечно с интервалом две секунды.

.loader__path {
  /* ... */
  animation: loader-stroke-anim 2s ease-in-out infinite;
}

@keyframes loader-stroke-anim {
  0% {
    stroke-dasharray: 1, 200;
    stroke-dashoffset: 0;
  }
  50% {
    stroke-dasharray: 90, 200;
    stroke-dashoffset: -45;
  }
  100% {
    stroke-dasharray: 1, 200;
    stroke-dashoffset: -180;
  }
}

Последний штрих

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

.loader__svg {
  animation: rotate 3s linear infinite;
}

@keyframes rotate {
  100% {
    transform: rotate(360deg);
  }
}

Готовый результат можно посмотреть в песочнице

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