Сложный круговой прогрессбар — 2 уровень | CSS Боль
Сначала просто смотрим на готовый результат.
Потом разберём, как собрать такой прогрессбар.
Берём за основу прошлое решение кругового прогрессбара без закруглений.
Здесь уже есть два слоя: бублик на radial-gradient и шкала на conic-gradient.
Начнём с настроек радиуса и ширины шкалы. Они изменяются за счёт синхронного сдвига колорстопов в верхнем градиенте.
Изменим позиции цвета вручную, чтобы увидеть эффект.
Делаем шкалу полупрозрачной.
Это временно: так лучше видно отдельные слои, из которых собирается компонент.
Теперь делаем полупрозрачным и радиальный градиент. Полупрозрачность уберём в конце.
Вводим CSS-переменную --progress.
Через неё дальше будем управлять длиной шкалы.
Подключаем --progress к conic-gradient.
Теперь шкала зависит от переменной, а не от жёсткого значения.
Добавляем --scale-radius — радиус шкалы.
Добавляем --scale-thikness для управления толщиной шкалы.
Вводим --_inner-r через calc().
Это внутренняя граница бублика.
Добавляем --_outer-r через calc().
Теперь обе границы кольца вычисляются из переменных.
Переводим radial-gradient на новые радиусы.
Пробуем уменьшить радиус.
Это просто проверка, что формулы работают правильно.
Возвращаем рабочий радиус.
Базовая форма снова на месте.
Теперь проверяем толщину.
Смотрим, что и этот параметр работает как задумано.
Возвращаем рабочую толщину.
Базовая геометрия готова.
Добавляем первый наконечник ещё одним фоновым слоем.
Для этого используем отдельный radial-gradient.
Вводим --_cap1-x. Это координата x центра наконечника.
Разберём выражение внутри calc(). 50% — точка отсчёта координат в центре блока. Косинус задаёт смещение относительно этой точки. Начальный угол -90deg в косинусе располагает наконечник в верхней точке шкалы.
Радиус окружности, на которой располагается наконечник, задаётся умножением косинуса на --scale-radius.
Вводим --_cap1-y. Это координата y центра наконечника.
Формула аналогична предыдущей, только вместо косинуса используется синус.
Подключаем var(--_cap1-x) и var(--_cap1-y) к radial-gradient, заменяя этими переменными координаты центра градиента.
Меняем радиус и смотрим на первый наконечник.
Это проверка, что он двигается вместе с окружностью.
Возвращаем рабочий радиус.
Дальше будет короткий эксперимент с углами.
Немного отвлечёмся от сложных формул и поиграем с углом в cos() и sin(), чтобы увидеть, как наконечник перемещается по кругу.
Для этого прибавим дополнительный угол 30deg к стартовому углу внутри синуса и косинуса.
Увеличиваем угол до 120deg, наконечник перемещается дальше по кругу.
Увеличиваем ещё раз, движение продолжается.
Сдвигаем точку ещё дальше по окружности. Теперь вы понимаете, как работает сочетание синуса и косинуса. И это пригодится для второго наконечника.
Удаляем дополнительный угол из координат первого наконечника.
Вводим --_angle через calc().
Здесь важно превратить --progress без единицы измерения в угол для следующих формул.
Добавляем второй наконечник.
Это ещё один radial-gradient, пока в статичной точке.
Появляется --_cap2-x.
Готовим координату x для второго наконечника.
Добавляем --_cap2-y.
Теперь вторую точку тоже можно двигать по формуле.
Внедряем новые переменные в градиент второго наконечника.
Уменьшаем --progress.
Проверяем, что второй наконечник двигается правильно.
Теперь увеличиваем --progress.
Снова проверяем движение на другом значении.
Меняем значение ещё раз. Всё работает. Отлично.
Подставляем в conic-gradient тот же --_angle, который используют наконечники. Это всего лишь небольшой рефакторинг.
Проверяем, что ничего не сломалось.
С другим значением.
Возвращаем нейтральное состояние.
Механика работает, можно завершать компонент.
Возвращаем бублику финальный цвет.
Временная полупрозрачность больше не нужна.
Финальный цвет получают шкала и оба наконечника.
Теперь весь прогрессбар выглядит как единое целое.
Теперь поиграемся с параметрами и убедимся, что всё работает. Меняем прогресс.
Меняем ещё раз.
Возвращаем прогресс 50 и увеличиваем радиус. Всё работает.
Уменьшаем радиус.
Возвращаем радиус шкалы 50px.
Увеличиваем толщину через --scale-thikness. Всё отлично.
Делаем прогрессбар тоньше.
Одновременно меняем радиус и толщину. И тоже всё работает.
Убираем эффект «зубцов» на краях шкалы. Для этого «раздвигаем» позиции цветов в соседних колорстопах на 1px.
Добавляем промежуточный цвет в radial-gradient, чтобы получить еле заметную обводку по краям бублика.
Теперь добавляем в разметку несколько прогрессбаров и экспериментируем с их параметрами.
Прогрессбар собран на чистом CSS, поэтому он отлично сочетается со всеми возможностями CSS. Его можно легко анимировать через @property и @keyframes.
Можно создать и более сложную анимацию, в которой изменяется не только прогресс, но и другие параметры шкалы (радиус + ширина).
Можно экспериментировать с экстремальным изменением параметров, чтобы получить необычные визуальные эффекты по мере заполнения шкалы.