scroll-driven animations можно освоить на одном небольшом проекте, если сразу видеть вход, действие и результат. Scroll-driven animations связывают прогресс CSS-анимации с прокруткой документа или появлением элемента в области просмотра. Ниже вы соберёте работающий пример и проверите обычный и граничный сценарии.
Обработчик scroll на JavaScript легко запускается слишком часто, смешивает измерения и стили и дёргает интерфейс на слабом устройстве. Поэтому отделим настройку, входные данные, основное действие и проверку. В этой статье вы соберёте страницу статьи с индикатором чтения сверху и мягким появлением карточек по мере прокрутки. Проверка: полоса растёт от 0 до 100 процентов, карточки появляются в заданном диапазоне, а без поддержки весь текст остаётся видимым.
создать progress и несколько карточек в длинной статье. Не расширяйте проект до первого успешного запуска.
полоса растёт вместе с документом. Проверяйте значение, а не отсутствие ошибки.
После успеха измените диапазон появления карточки и предскажите точку завершения до запуска. Так копирование станет практикой.
Как устроен учебный проект scroll-driven animations
Одна анимация использует scroll timeline документа, другая создаёт view timeline для каждой карточки. CSS связывает timeline с keyframes. Держите ввод, логику и отображение раздельно: тогда каждый этап можно проверить отдельно.
| Этап | Действие | Проверяемый результат |
|---|---|---|
| Разметка | создать progress и несколько карточек в длинной статье | контент полностью читается без анимации |
| Индикатор | связать scaleX с animation-timeline: scroll() | полоса растёт вместе с документом |
| Карточки | использовать view() и animation-range | элемент появляется при входе в viewport |
| Fallback | обернуть улучшение в @supports и reduced motion | неподдерживаемый браузер показывает обычную страницу |
Контрольные точки: разметка, индикатор, карточки и fallback. Следующий шаг начинается после совпадения с ожидаемым результатом.

От входных данных до видимого результата. Сначала проверяется вход, затем действие и только потом интерфейс.
Собираем рабочий пример шаг за шагом
Пример сверялся с актуальной документацией MDN Scroll-driven animations на 19 октября 2026 года. Создайте один index.html и styles.css, затем откройте через локальный сервер в актуальном браузере. Проверьте текущую папку через pwd или Get-Location. Вставьте пример целиком, выполните один раз, затем разбирайте по частям.
.reading-progress {
position: fixed;
inset: 0 0 auto;
height: 6px;
background: #0d7cff;
transform: scaleX(0);
transform-origin: left;
animation: reading linear;
animation-timeline: scroll();
}
@keyframes reading {
to { transform: scaleX(1); }
}
@supports (animation-timeline: view()) {
.lesson-card {
animation: reveal both linear;
animation-timeline: view();
animation-range: entry 10% cover 35%;
}
}
@keyframes reveal {
from { opacity: 0; transform: translateY(24px); }
to { opacity: 1; transform: translateY(0); }
}- Синяя полоса сверху пропорциональна общей прокрутке документа.
- Каждая карточка анимируется собственной view timeline только при входе в область просмотра.
- Повторный запуск даёт тот же предсказуемый результат.
- Пустой ввод получает понятное сообщение вместо падения.
scroll() измеряет прокрутку контейнера, а view() измеряет положение конкретного элемента относительно scrollport. Найдите в примере вход, проверку и место формирования результата.

Что отличает устойчивый проект от случайного запуска. Явные границы делают ошибку локальной и понятной.
Что происходит внутри и почему это работает
Обычная временная анимация меняется от 0 до duration. Здесь роль времени играет прогресс прокрутки. animation-range выбирает часть timeline, в которой keyframes проходят от начала до конца. Логику держите отдельно от вывода: функция получает аргумент и возвращает значение, а интерфейс показывает его. Флаг both сохраняет начальное и конечное состояния вне активного диапазона, но базовый CSS не должен делать контент невидимым в браузере без поддержки.
| Часть | За что отвечает | Что проверить |
|---|---|---|
| Keyframes | описывают начальный и конечный визуальный вид | конечный кадр читаем и не меняет layout |
| Timeline | задаёт источник прогресса scroll() или view() | анимация движется только при прокрутке |
| Range | ограничивает участок входа и покрытия элемента | эффект заканчивается до центра экрана |
Для плавности меняйте transform и opacity, а не высоту и позиционные свойства, вызывающие перерасчёт layout. Не связывайте с прокруткой жизненно важные элементы управления. Пользователь должен видеть кнопку и читать текст независимо от эффекта. Не прячьте поток в одном обработчике: сохраните вход, проверьте его, вызовите операцию и только затем обновите интерфейс.
Проверяем проект и добавляем свою функцию
Добавьте шкалу прогресса внутри одного длинного раздела через именованный scroll timeline и сравните её с прогрессом всей страницы. До правки запишите ожидаемое поведение одним предложением. После граничного теста повторите обычный сценарий.
- Сохраните ожидаемый результат: полоса растёт от 0 до 100 процентов, карточки появляются в заданном диапазоне, а без поддержки весь текст остаётся видимым.
- Измените правило: измените диапазон появления карточки и предскажите точку завершения до запуска. Сначала предскажите итог.
- Передайте граничное значение и убедитесь, что приложение не падает.
- Верните корректные данные и объясните роли трёх основных частей.
- контент полностью читается без анимации
- полоса растёт вместе с документом
- элемент появляется при входе в viewport
- неподдерживаемый браузер показывает обычную страницу
CSS timeline убирает ручной scroll listener, но дизайн диапазона и доступности всё равно остаётся задачей разработчика. Полезная правка проходит от нового ввода до видимого результата.

Четыре проверки перед следующим шагом. Каждый следующий этап начинается после наблюдаемого результата.
Что запомнить и куда двигаться дальше
Проверьте клавиатурную прокрутку, мобильную ширину, reduced motion и очень короткую страницу. Индикатор не должен перекрывать фокус и навигацию. Для закрепления откройте в статье про тёмную тему, в View Transitions API и в практическом лендинге.
Как изучить тему в Кодике
Повторите keyframes, transform, overflow и viewport, затем добавляйте timeline. Сначала восстановите главную функцию и проверьте её на трёх значениях.
| Шаг | Что разобрать | Мини-проверка |
|---|---|---|
| 1. Основа | CSS-анимации, transform и fixed-позиционирование | Объясните вход и выход функции. |
| 2. Инструмент | scroll(), view() и animation-range | Повторите команду по памяти. |
| 3. Проект | Индикатор чтения и появление карточек | Проверьте два сценария. |
| 4. Рефакторинг | Именованные timeline и тест доступности | Разделите ввод, логику и вывод. |
Попробуйте убрать JavaScript-обработчик из старого демо, сохранив тот же результат и хороший fallback. Базовый синтаксис закрепите через курс CSS.
Opacity: 0 применяется всегда, а timeline не поддерживается. Помещайте улучшение в @supports.
Изменение top или height может дёргать страницу. Используйте transform и opacity.
Карточка остаётся полупрозрачной слишком долго. Завершайте эффект раньше.
Прокручиваемое движение может мешать. Отключайте или сокращайте эффект.
Что получится в итоге

Так выглядит законченный учебный проект: есть понятный вход, видимый результат, защита от неверных данных и место для следующего улучшения.
Чем scroll() отличается от view()?
scroll() связан с прогрессом прокрутки контейнера, view() с положением конкретного элемента в области просмотра.
Нужен ли requestAnimationFrame?
Нет. Прогрессом управляет CSS timeline браузера.
Что проверять первым, если scroll-driven animations не запускается?
Версию среды, текущую папку, команду запуска и первую строку ошибки.
Как понять, что проект scroll-driven animations работает?
Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай.
Можно ли начать с готового кода?
Да. Добейтесь результата, измените одно правило и восстановите ключевую функцию без копирования.
Выберите одно улучшение и проведите его от ввода до результата.
Если не хватает основы, перейдите курс CSS, затем восстановите ключевую функцию без подсказки.