TGViewer
Логово верстальщика Логово верстальщика @webdevlair · 7.97K subscribers
Post #4549 338
⁣Сегодня покажу, как выкинуть JS из связки «скролл + эффекты». Речь про CSS scroll-driven animations — это уже не polyfill, а нативный API в Chrome/Edge/Safari 26+. Два главных героя: scroll() и view(). Поехали.

**Основы**

scroll() привязывает анимацию к прогрессу прокрутки контейнера. Элемент просто крутится/двигается/закрашивается в зависимости от того, сколько пикселей мы проскроллили.

view() привязывает анимацию к появлению элемента во вьюпорте. Элемент «оживает», когда вползает в кадр, и «умирает», когда выходит. И это идеально для параллакса или плавного появления карточек.

Оба механизма работают через animation-timeline, а за точками старта и конца управляет animation-range.

**Прогресс-бар без единой строчки JS**

Классика: полоска сверху показывает, сколько прочитано. Раньше — слушатель скролла и requestAnimationFrame. Теперь — 5 строк CSS:

.progress {
position: fixed;
top: 0; left: 0;
width: 100%; height: 4px;
background: #ff4d00;
transform-origin: left;
animation: scale linear;
animation-timeline: scroll();
}

@keyframes scale {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}


Всё. scroll() без аргументов = отслеживаем скролл ближайшего предка (или корня, если предка-скроллера нет). Анимация идёт ровно от верха страницы до низа.

**Параллакс через view()**

Берём картинку, которая должна двигаться с другой скоростью, пока она на экране. Вместо scroll-слушателя и пересчёта позиций:

.parallax-image {
animation: drift linear;
animation-timeline: view();
animation-range: entry 0% cover 40%;
}

@keyframes drift {
from { transform: translateY(15%); }
to { transform: translateY(-15%); }
}


Поясню значения entry, cover, exit. Палитра простая:
- entry — элемент выезжает снизу/сверху в кадр
- cover — полностью на экране
- exit — покидает вьюпорт

entry 0% cover 40% значит: анимация начинается в момент появления и заканчивается, когда элемент прошёл 40% высоты экрана. За счёт этого картинка «сдвигается» независимо от скорости скролла.

**Важный нюанс: animation-range**

Если у вас контейнер высотой 200%, а анимация должна идти только на середине скролла — играйтесь именно через range. scroll(root) + range: 0% 50% даст эффект, заканчивающийся на половине страницы. Это заменяет кучу логики «если y > X».

**Бонус-фича: animation-timeline: view(block)**

По умолчанию отслеживается ось блока (вертикаль) или инлайна (горизонталь). Можно явно указать view(inline) для горизонтальных слайдеров-каруселей с прокруткой по X. Тоже без JS.

**Что под капотом и поддержка**

Работает только с ключевыми кадрами — CSS-переходы так не умеют. animation-timeline можно комбинировать с обычной animation-duration, но при наличии timeline длительность игнорируется: прогрессом правит скролл.

Поддержка в 2025-м: Chrome 115+, Edge 115+, Safari 26+ (с префиксом -webkit- в iOS 26). Firefox — за флагом, но уже в активной разработке. Для отстающих браузеров это деградирует безболезненно: без поддержки просто не будет анимации.

**Моя рекомендация**

Не пишите свой параллакс через JS, если это обычный маркетинговый лендинг. Нативный scroll-driven API считается на стороне compositor, поэтому дёрганий и микролагов на слабых устройствах меньше, чем при ручном обновлении свойств из JS.

Вывод: добавьте scroll() на прогресс-бар, view() на карточки — почувствуете разницу в скорости вёрстки сразу.
  • 🔥 1
More from @webdevlair
  1. Sep 25, 2026⁣CSS :nth-child(An+B of S) - сложные выборки без JS Раньше «каждый второй среди подходящих…
  2. Sep 25, 2026Post #4631
  3. Sep 25, 2026Кто-то из Anthropic скинул годный трюк для Opus 5.5. Суть простая: в Claude Code дёрни /cl…
  4. Sep 25, 2026Post #4629
  5. Sep 24, 2026Claude Opus 5.5 не где-то там — она уже здесь, и в большинстве бенчмарков она укладывает н…
  6. Sep 24, 2026Post #4626
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →