Раньше, чтобы сделать круговой прогрессбар, мы страдали с SVG. Мне до сих пор больно заглядывать в инспектор на старых реализациях. Сегодня всё кардинально упростилось.

Современный CSS позволяет собрать сложный, гибкий и красивый круговой прогрессбар буквально на одном div и на одном CSS‑свойстве. И всё это — с отличной браузерной поддержкой.

В этой статье я разберу именно этот приём. Сначала — ключевую идею подхода, затем — возможности кастомизации, после этого добавлю немного визуальной «дороговизны», удобные ручки управления и экспериментальную CSS‑логику. Да‑да, напоследок мы немного попрограммируем на CSS!

Ключевой приём и базовая реализация

Начнём с главного. Вся реализация строится вокруг одного элемента:

<div class="progress"></div>

И одного свойства — background-image с несколькими фоновыми изображениями. Ключевой приём заключается в следующем:

  • верхний фон — радиальный градиент, который формирует форму шкалы;

  • нижний фон — конический градиент, который отвечает за заполнитель.

Вот базовый CSS:

.progress {
  width: 150px;
  height: 150px;
  background-image:
    radial-gradient(
      circle,
      #222 0% 27%,
      transparent 28% 50%,
      #222 51%
    ),
    conic-gradient(
      #D64E42 0% 60%,
      transparent 60%
    );
}

Радиальный градиент сверху создаёт «бублик» — шкалу с вырезанной прозрачной серединой. Конический градиент снизу заливает сектор круга, то есть управляет заполнителем шкалы.

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

Базовая реали��ация кругового прогрессбара
Базовая реализация кругового прогрессбара

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


Кастомизация: ширина шкалы и прозрачность

Одна из приятных особенностей этого подхода — он очень легко кастомизируется.

Ширина шкалы — задаётся параметрами верхнего, радиального, градиента. Для этого играем с позициями цвета в колорстопах:

radial-gradient(
  circle,
  #222 0% 30%,
  transparent 31% 54%,
  #222 55%
)

Цвет и прозрачность шкалы и заполнителя — задаются параметрами нижнего, конического, градиента. Меняем цвет в первом колорстопе на полупрозрачный — и заполнитель становится полупрозрачным. Меняем цвет во втором колорстопе — и изменяется пустая часть шкалы.

conic-gradient(
  rgba(214, 78, 66, 0.6) 0% 60%,
  transparent 60%
)

Никаких дополнительных элементов, масок или вычислений. Только параметры градиентов.

Изменяем ширину шкалы и прозрачность заполнителя
Изменяем ширину шкалы и прозрачность заполнителя

Хэштег #неколхоз: текстура, рамки и тени

Базовая версия готова, но выглядит довольно колхозно. Добавим немного «дороговизны».

Во‑первых, добавим третий фоновый слой — повторяющийся конически градиент, который создаёт эффект радиальных секций:

repeating-conic-gradient(
  rgba(0, 0, 0, 0.3),
  rgba(0, 0, 0, 0.2) 4.5%,
  transparent 5%
)

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

radial-gradient(
  circle,
  #222 0% 27%,
  #333,
  transparent 28% 50%,
  #333,
  #222 51%
)

И в финале — слегка закруглим сам блок прогрессбара и добавим тени:

.progress {
  border-radius: 10px;
  box-shadow: inset 0 0 1px #666, 0 0 30px black;
}

Всё это не влияет на логику компонента — только на внешний вид.

Итоговая стилизация
Итоговая стилизация

Ручки управления: CSS-переменные

Теперь давайте сделаем прогрессбар удобным для использования в реальных интерфейсах. Для этого добавим CSS‑переменную --progress.

.progress {
  --progress: 45;
  --corner: calc(1% * var(--progress, 0));
  background-image:
    radial-gradient(
      circle,
      #222 0% 27%,
      #333,
      transparent 28% 50%,
      #333,
      #222 51%
    ),
    conic-gradient(
      #D64E42 0% var(--corner),
      transparent var(--corner)
  );
}

Теперь прогресс задаётся понятным числом от 0 до 100, а CSS сам пересчитывает его в нужный угол.

Можно легко создать несколько экземпляров компонента:

<div class="progress" style="--progress: 15"></div>
<div class="progress" style="--progress: 50"></div>
<div class="progress" style="--progress: 90"></div>
Управление прогрессом с помощью CSS-переменной
Управление прогрессом с помощью CSS-переменной

Экспериментальные CSS-фичи: условная логика

А теперь давайте немного заглянем в будущее CSS. В современных версиях Chrome уже можно использовать условную логику с помощью if().

Например, можно менять цвет шкалы в зависимости от значения прогресса:

.progress {
  --color: if(
    style(--progress <= 33): #D64E42;
    style(--progress <= 66): #F5B848;
    style(--progress <= 99): #58B473;
    else: white;
  );
}

И использовать этот цвет в градиенте:

conic-gradient(
  var(--color) 0% var(--corner),
  transparent var(--corner)
)

Можно добавить подпись в центре прогрессбара, которая меняется в зависимости от значения прогресса. Добавляем псевдоэлемент, используем if() в свойстве content, чтобы привязать текст подписи к значениям прогресса. Для цвета подписи используем CSS‑переменную --color из родителя.

.progress {
  display: flex;
  justify-content: center;
  align-items: center;
}

.progress::before {
  content: if(
    style(--progress <= 33): "low";
    style(--progress <= 66): "med";
    style(--progress <= 99): "high";
    else: "go!";
  );
  color: var(--color);
}

Важно: это экспериментальные возможности. Если нужна хорошая поддержка, то используйте JS вместе с классами‑модификаторами.

Условная стилизация в зависимости от прогресса
Условная стилизация в зависимости от прогресса

Вау-эффект: нативная анимация

И напоследок — самое приятное. Этот прогрессбар отлично совместим с нативной CSS‑анимацией.

Для этого регистрируем переменную --progress:

@property --progress {
  inherits: true;
  initial-value: 0;
  syntax: "<number>";
}

И анимируем её:

.progress {
  animation: progress 10s infinite alternate;
}

@keyframes progress {
  to {
    --progress: 100;
  }
}

Во время анимации автоматически меняется:

  • размер заполнителя,

  • цвет шкалы,

  • подпись в центре.

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

Анимация прогрессбара
Анимация прогрессбара

Заключение

Ключевой приём во всей этой истории — множественные фоны с радиальным и коническим градиентами. Он прост, хорошо поддерживается и даёт большую гибкость.

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

Если нужен надёжный продакшен‑компонент — используйте базовый приём. Если хочется поэкспериментировать и поддержка позволяет — используйте новые возможности. Они доступны в свежих версиях Chrome.

Надеюсь, вам будет приятнее делать прогрессбары в 2026 году!

Подписывайтесь на мой телеграм‑канал «CSS Боль», если хотите ещё больше интересного современного CSS и задавайте вопросы в комментариях.