Skip to content
F Fastry
astro-rocket функции ux анимация

Кольцо прогресса прокрутки — круговой индикатор на кнопке «Наверх»

Кнопка «Наверх» в Fastry теперь имеет круговое SVG-кольцо прогресса, которое заполняется по мере прокрутки.

A

Almaz

2 мин. чтения

“Кнопка «Наверх» в Fastry была обновлена круговым кольцом прогресса прокрутки. По мере прокрутки страницы вниз кольцо заполняется по часовой стрелке вокруг кнопки — давая читателю визуальное представление о том, сколько страницы он уже просмотрел. Нажатие на кнопку по-прежнему возвращает в начало страницы.

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

Трёхслойная структура

Кнопка построена из трёх слоёв, расположенных друг над другом.

Слой 1 — внешняя кнопка размером 48 × 48 px (h-12 w-12), зафиксирована в правом нижнем углу окна просмотра. Она содержит два других слоя и управляет анимацией появления/скрытия через opacity и translate.

Слой 2 — SVG-кольцо находится в absolute inset-0, заполняя кнопку полностью. В нём две окружности:

  • Фоновая дорожка (class=\"text-border\", opacity=\"0.5\") показывает полный путь кольца, чтобы читатель видел, где появится дуга прогресса.
  • Дуга прогресса (id=\"back-to-top-ring\", class=\"text-brand-500\") анимируется через stroke-dashoffset.

Обе окружности используют stroke=\"currentColor\", поэтому их цвет наследуется от Tailwind-класса текста — никакого жёстко заданного hex или CSS-переменной в разметке SVG.

Слой 3 — внутренняя лицевая панель — это <span> с отступом 5 px (absolute inset-[5px]), стилизованный как пилюля с фоном сайта, границей и тенью. Внутри — SVG-иконка стрелки вверх.

<button id=\"back-to-top\" class=\"fixed bottom-6 right-6 z-50 h-12 w-12 ...\">

  <!-- Кольцо -->
  <svg class=\"absolute inset-0 h-full w-full -rotate-90\" viewBox=\"0 0 48 48\" aria-hidden=\"true\">
    <circle cx=\"24\" cy=\"24\" r=\"21\" fill=\"none\"
      stroke=\"currentColor\" class=\"text-border\"
      stroke-width=\"2\" opacity=\"0.5\" />
    <circle id=\"back-to-top-ring\" cx=\"24\" cy=\"24\" r=\"21\" fill=\"none\"
      stroke=\"currentColor\" class=\"text-brand-500\"
      stroke-width=\"2.5\" stroke-linecap=\"round\"
      stroke-dasharray=\"131.95\" stroke-dashoffset=\"131.95\" />
  </svg>

  <!-- Лицевая панель -->
  <span class=\"absolute inset-[5px] flex items-center justify-center
               rounded-full bg-background border border-border-strong
               text-foreground-muted shadow-md\" aria-hidden=\"true\">
    <!-- иконка стрелки вверх -->
  </span>

</button>

SVG повёрнут на -90°, чтобы штрих начинался в позиции 12 часов, а не 3 часов.

Математика кольца

Дуга прогресса анимируется изменением одного CSS-свойства: stroke-dashoffset.

Радиус окружности — 21 px. Длина окружности:

2 × π × 21 ≈ 131.95

И stroke-dasharray, и начальный stroke-dashoffset установлены в 131.95. Когда offset равен полной длине окружности, дуга невидима — штрих начинается и заканчивается в одной точке, поэтому ничего не рисуется. По мере уменьшения offset к 0 появляется всё больше дуги.

На каждом кадре прокрутки:

var scrollable = document.documentElement.scrollHeight - window.innerHeight;
var pct = scrollable > 0 ? window.scrollY / scrollable : 0;
ring.style.strokeDashoffset = String(CIRCUMFERENCE * (1 - pct));

В верхней части страницы pct равен 0, поэтому strokeDashoffset равен 131.95 — дуга скрыта. Внизу pct равен 1, поэтому strokeDashoffset равен 0 — дуга полностью видна.

Троттлинг через requestAnimationFrame

Обработчик прокрутки использует паттерн с флагом ticking, чтобы ограничить обновления одним кадром анимации:

var ticking = false;

function onScroll() {
  if (!ticking) {
    ticking = true;
    requestAnimationFrame(updateFrame);
  }
}

window.addEventListener('scroll', onScroll, { passive: true });

updateFrame сбрасывает ticking в false в конце каждого кадра, позволяя следующему событию прокрутки запланировать новое обновление. В сочетании с { passive: true } это гарантирует, что обработчик прокрутки никогда не блокирует основной поток.

Автоматический цвет темы

Цвет кольца не требует JavaScript для отслеживания активной темы. Дуга прогресса имеет class=\"text-brand-500\" и stroke=\"currentColor\". Tailwind связывает text-brand-500 с --color-brand-500 через блок @theme в global.css, а stroke=\"currentColor\" наследует CSS-значение color из этого класса.

Когда посетитель выбирает другой цвет в переключателе тем — Orange, Emerald, Violet или любую из двенадцати доступных тем — браузер устанавливает новый атрибут data-theme на <html>. Каждый файл темы переназначает --brand-500 на другой OKLCH-цвет. Все элементы, использующие text-brand-500 или stroke=\"currentColor\", перекрашиваются автоматически. Кольцо — один из таких элементов, поэтому оно меняет цвет в тот же момент, что и логотип, индикатор прогресса в шапке, основные кнопки и все остальные детали страницы в брендовых цветах.

Никакого дополнительного JavaScript. Никакого слушателя события смены темы. Каскад делает всё сам.

Очистка при навигации

Fastry использует Astro View Transitions для клиентской навигации между страницами. Поскольку скрипт кнопки «Наверх» — is:inline и выполняется один раз при первой загрузке, его слушатель прокрутки накапливался бы при переходах между страницами. Скрипт удаляет слушатель перед каждой сменой страницы:

document.addEventListener('astro:before-swap', function () {
  window.removeEventListener('scroll', onScroll);
}, { once: true });

{ once: true } гарантирует, что этот слушатель очистки сам удаляется после срабатывания, поэтому он тоже не накапливается. Функция инициализации защищает от двойной инициализации с помощью флага data-btt-init на элементе кнопки.

Порог показа/скрытия

Кнопка — и кольцо — остаются скрытыми, пока посетитель не прокрутит ниже 400 px. Ниже этого порога кольцо показывало бы слишком мало прогресса, и кнопка была бы бесполезной. После пересечения порога кнопка плавно появляется, и кольцо сразу отображает правильную позицию.

if (window.scrollY > THRESHOLD) {
  btn.classList.remove('opacity-0', 'translate-y-2', 'pointer-events-none');
  btn.classList.add('opacity-100', 'translate-y-0');
}

Переход полностью обрабатывается Tailwind-классами transition-[opacity,transform] duration-200 на внешней кнопке — никаких встроенных transition-стилей не требуется.

Связанные функции

Кольцо прогресса прокрутки дополняет две другие функции UX, связанные с прокруткой, в Fastry:

  • Индикатор прогресса прокрутки — линия толщиной 2 px в брендовом цвете в шапке сайта, заполняющаяся по мере прокрутки.
  • Анимации появления при прокрутке — элементы с атрибутом data-reveal появляются с эффектом затухания и сдвига при входе в область видимости, работают через IntersectionObserver.

Обе также используют --color-brand-500 и автоматически обновляются при изменении активной темы.”

Поделиться:

Похожие записи

Индикатор прокрутки Hero — только для десктопа, скрывается при скролле

Hero в Fastry имеет анимированный индикатор прокрутки: два подпрыгивающих шеврона, которые появляются после анимации hero и исчезают при начале прокрутки.

A Almaz
1 мин. чтения
astro-rocket функции ux анимация

Панель прогресса прокрутки — прогресс чтения с одного взгляда

Fastry теперь имеет панель прогресса прокрутки: тонкая линия брендового цвета, которая заполняется по мере прокрутки. Узнайте, как это работает и как включить на любой странице.

A Almaz
2 мин. чтения
astro-rocket функции шапка ux

Комментарии к постам блога — Giscus с ленивой загрузкой

Fastry поддерживает комментарии в блоге на основе Giscus и GitHub Discussions. Скрипт загружается лениво — читатели платят нулевую стоимость, если не прокручивают до низа.

A Almaz
2 мин. чтения
astro-rocket функции блог комментарии giscus

Подписывайтесь

Будьте в курсе — новые статьи, мысли и обновления.