CSS-анимации на основе прокрутки: 5 паттернов анимации прокрутки на чистом CSS без JavaScript
CSS-анимации на основе прокрутки: Плавная прокрутка без JS
Параллакс с JS-слушателями прокрутки вызывает подтормаживания, многословный код IntersectionObserver, накладные расходы производительности requestAnimationFrame — анимации прокрутки долгое время зависели от JavaScript. CSS-анимации на основе прокрутки позволяют реализовать параллакс, индикаторы прогресса и анимации появления исключительно на CSS: ноль JS, 60fps, автоматическое GPU-ускорение. В 2026 году CSS-анимации на основе прокрутки полностью поддерживаются в Chrome и Safari.
Эта статья охватывает 5 основных паттернов, проводя вас через scroll-timeline → view-timeline → параллакс → индикатор прогресса → анимации появления.
Основные концепции
| Концепция | Описание |
|---|---|
| scroll-timeline | Временная шкала анимации на основе позиции прокрутки |
| view-timeline | Временная шкала анимации на основе видимости элемента |
| animation-timeline | Указывает, какую временную шкалу прокрутки использует анимация |
| animation-range | Начальная и конечная позиции анимации в диапазоне прокрутки |
| scroll() | Анонимная функция временной шкалы прокрутки |
| view() | Анонимная функция временной шкалы видимости |
| scroll-progress | Прогресс прокрутки 0-1 |
| view-progress | Прогресс видимости 0-1 |
Анализ проблем: 5 главных проблем CSS-анимаций прокрутки
- Совместимость браузеров: Поддержка Firefox отстаёт
- Сложная отладка: Поддержка анимаций прокрутки в DevTools ограничена
- Вложенная прокрутка: Конфигурация контейнеров прокрутки, отличных от документа, сложна
- Вычисление диапазона анимации: Процент animation-range имеет высокую стоимость понимания
- Запасной вариант: Неподдерживаемые браузеры нуждаются в JS-фоллбэке
Пошагово: 5 паттернов CSS-анимаций прокрутки
Паттерн 1: Анимация прогресса прокрутки с scroll-timeline
/* Индикатор прогресса вверху страницы */
@keyframes progress-bar {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
.progress-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
background: linear-gradient(90deg, #6366f1, #ec4899);
transform-origin: left;
animation: progress-bar linear;
animation-timeline: scroll(root);
}
Паттерн 2: Анимация появления в области просмотра с view-timeline
@keyframes reveal-up {
from {
opacity: 0;
transform: translateY(60px) scale(0.95);
filter: blur(4px);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
filter: blur(0);
}
}
.card {
animation: reveal-up linear both;
animation-timeline: view();
animation-range: entry 0% entry 80%;
}
Паттерн 3: Эффект параллакс-прокрутки
@keyframes parallax-slow {
from { transform: translateY(0); }
to { transform: translateY(-100px); }
}
@keyframes parallax-fast {
from { transform: translateY(0); }
to { transform: translateY(-300px); }
}
.parallax-bg {
animation: parallax-slow linear both;
animation-timeline: scroll(root);
}
.parallax-fg {
animation: parallax-fast linear both;
animation-timeline: scroll(root);
}
Паттерн 4: Именованная временная шкала прокрутки
.scroller {
overflow-y: auto;
scroll-timeline-name: --my-scroller;
scroll-timeline-axis: block;
}
@keyframes rotate-icon {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.rotating-icon {
animation: rotate-icon linear;
animation-timeline: --my-scroller;
}
Паттерн 5: Сложные последовательности анимаций
@keyframes hero-sequence {
0% {
opacity: 0;
transform: translateY(100px) scale(0.8);
filter: blur(10px);
}
30% {
opacity: 1;
transform: translateY(0) scale(1);
filter: blur(0);
}
70% {
opacity: 1;
transform: translateY(0) scale(1);
}
100% {
opacity: 0;
transform: translateY(-50px) scale(0.95);
}
}
.hero-title {
animation: hero-sequence linear both;
animation-timeline: view();
animation-range: entry 0% exit 100%;
}
Руководство по подводным камням
Подводный камень 1: Не указан animation-timeline
/* ❌ Неправильно: отсутствует animation-timeline */
.element {
animation: slide-in 1s linear;
/* Анимация не будет следовать за прокруткой */
}
/* ✅ Правильно: указать временную шкалу прокрутки */
.element {
animation: slide-in linear both;
animation-timeline: view();
}
Подводный камень 2: Неверные значения animation-range
/* ❌ Неправильно: диапазон превышает диапазон прокрутки */
.element {
animation-range: entry 0% entry 200%; /* 200% недопустимо */
}
/* ✅ Правильно: использовать допустимый диапазон */
.element {
animation-range: entry 0% entry 100%;
}
Подводный камень 3: Конфликт transform с прокруткой
/* ✅ Правильно: использовать подсказку will-change */
.parallax {
animation: parallax linear both;
animation-timeline: scroll(root);
will-change: transform;
}
Подводный камень 4: Отсутствие обработки фоллбэка
/* ✅ Правильно: предоставить фоллбэк */
@supports (animation-timeline: view()) {
.card {
animation: reveal-up linear both;
animation-timeline: view();
}
}
@supports not (animation-timeline: view()) {
.card { opacity: 1; transform: none; }
}
Подводный камень 5: Контейнер прокрутки без overflow
/* ✅ Правильно: убедиться, что контейнер прокручивается */
.scroller {
overflow-y: auto;
scroll-timeline-name: --my-scroll;
}
Устранение ошибок
| # | Ошибка | Причина | Решение |
|---|---|---|---|
| 1 | Анимация не следует за прокруткой | Не задан animation-timeline | Добавить animation-timeline: view() или scroll() |
| 2 | Анимация заканчивается рано | animation-range слишком мал | Увеличить диапазон |
| 3 | Неверное направление параллакса | scroll-timeline-axis настроен неверно | Использовать block/inline для направления |
| 4 | Именованная временная шкала недействительна | scroll-timeline-name не совпадает | Убедиться, что имена родителя и потомка совпадают |
| 5 | Подтормаживание анимации | Нет will-change | Добавить will-change: transform |
| 6 | Firefox не работает | Браузер не поддерживает | Использовать @supports для фоллбэка |
| 7 | Вложенная прокрутка не работает | Конфликт внутренней/внешней прокрутки | Использовать именованный scroll-timeline |
| 8 | Анимация дёргается | Ключевые кадры недостаточно плавные | Добавить больше ключевых кадров или использовать linear |
| 9 | Фиксированные элементы работают некорректно | transform влияет на фиксированное позиционирование | Переместить фиксированные элементы вне контейнера transform |
| 10 | На мобильных не плавно | GPU-ускорение не включено | Добавить transform: translateZ(0) |
Продвинутая оптимизация
- Scroll Snap + анимации прокрутки: Комбинация постраничной прокрутки с анимациями
- Пользовательские свойства CSS Houdini: Регистрация свойств анимации для сложных эффектов
- prefers-reduced-motion: Уважать предпочтение пользователя о снижении движения
- Container queries + анимации прокрутки: Синергия адаптивности и анимации прокрутки
- WAAPI + Scroll Timeline: Web Animations API в сочетании с CSS-временными шкалами прокрутки
Сравнение
| Измерение | CSS Scroll-Driven | JS IntersectionObserver | Событие scroll JS | GSAP ScrollTrigger |
|---|---|---|---|---|
| Производительность | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| Объём кода | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| Поддержка браузеров | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Гибкость | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Лёгкость отладки | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Кривая обучения | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
Итоги: CSS-анимации на основе прокрутки позволяют достичь плавных эффектов прокрутки с нулём JS, значительно превосходя JS-решения. CSS-анимации прокрутки подходят для сценариев взаимодействия прокрутки, где требуется максимальная производительность, особенно параллакс, индикаторы прогресса и анимации появления. С полной поддержкой Chrome и Safari в 2026 году используйте с фоллбэком @supports.
Онлайн-инструменты
- Форматирование JSON: /ru/json/format
- Калькулятор хешей: /ru/encode/hash
- cURL в код: /ru/dev/curl-to-code
Попробуйте эти локальные браузерные инструменты — регистрация не требуется →