TGViewer
Логово верстальщика Логово верстальщика @webdevlair · 7.96K subscribers
Post #4374 528
⁣CSS :has() + scroll-driven-анимации — реактивные хедеры без JS

Связка селектора :has() и scroll-driven анимаций позволяет управлять состоянием UI-элементов по скроллу без единой строчки JavaScript. Раньше для sticky-хедеров, меняющих тень по скроллу, или сайдбаров с плавающим появлением тащили Intersection Observer или слушали scroll — теперь это решается чисто CSS. Основная ошибка: верстальщики продолжают использовать тяжелые JS-обвязки для задач, которые браузер уже умеет в потоке композитинга.

Как работает связка

Создаешь невидимый маркер внутри контента — обычный div с scroll-driven анимацией прозрачности. Затем на контейнере через :has() проверяешь состояние этого маркера: если он анимировался (значение opacity изменилось), значит, скролл прошел заданный порог. Пример для сайдбара:

.marker {
animation: markerAnim linear;
animation-timeline: scroll();
}
@keyframes markerAnim {
0% { opacity: 0; }
100% { opacity: 1; }
}
body:has(.marker[style*="opacity: 1"]) .sidebar {
transform: translateX(0);
box-shadow: 2px 0 10px rgba(0,0,0,0.2);
}


Маркер не занимает места, не ломает layout, а анимация выполняется в отдельном потоке — без пересчета layout и repaint. Подходит для динамических хедеров с blur-эффектом, сайдбаров, floating-кнопок и control-панелей в дашбордах.

Production-контекст и trade-offs

Реальный пример: в админке e-commerce при скролле таблицы заказов нужно показывать панель фильтров, которая прилипает к верху и скрывает лишние контролы. Через :has() + scroll() это делается декоративным маркером на первом скролле страницы. Важно: :has() внутри стилей для ключевых элементов (body, main) может редко, но снижать производительность в больших документах с тысячами DOM-узлов. Практический совет: используй маркер с position: absolute и нулевыми размерами, чтобы избежать дополнительного reflow.

Ошибка: состояние через класс, а не через свойство

Типичная ошибка — пытаться проверять класс маркера, который не меняется при scroll-driven анимациях. Классы изменяются только через JS или через CSS-анимации с animation-fill-mode: forwards и интерполяцией opacity. Всегда проверяй через [style*="..."] или используй CSS-хуки через @property для кастомных свойств. Для старых браузеров без поддержки :has() оставляй Intersection Observer как фолбэк через @supports not selector(:has()).

Вывод: CSS :has() с scroll-driven анимациями — инженерный компромисс между производительностью и браузерной поддержкой, который уже сегодня решает задачи реактивных интерфейсов без JS.
  • 👍 2
More from @webdevlair
  1. Sep 27, 2026Бумага и ручка: стартап заставил соискателей писать сопроводительные вручную Стартап Dumb…
  2. Sep 27, 2026Post #4644
  3. Sep 27, 2026Сигналы добрались до React-Redux В React Status #492 — React-Redux 9.4 Alpha притащил опци…
  4. Sep 27, 2026Post #4642
  5. Sep 26, 2026500+ баксов в месяц за ChatGPT? Не, у нас столько не завалялось Запуска пока нет. Но новый…
  6. Sep 26, 2026Post #4640
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 →