Современные возможности CSS, для которых больше не нужен JavaScript
Годами фронтенд-разработчики обращались к JavaScript для реализации интерактивных UI-паттернов. Для аккордеонов требовались обработчики кликов. Для всплывающих подсказок — библиотеки позиционирования. Для адаптивных компонентов — resize observers. Эта эра подходит к концу.
Современный CSS теперь обрабатывает стилизацию с учётом состояния, брейкпоинты на уровне компонентов, эффекты на основе прокрутки и нативные поповеры — всё это без единой строки JavaScript. Это не экспериментальные возможности. Они стабильны, широко поддерживаются и готовы к использованию в продакшене в 2025 году.
Ключевые выводы
- CSS-селектор
:has()позволяет стилизовать родительские элементы на основе состояния дочерних, устраняя необходимость в JavaScript для стилизации валидации форм и интерактивных компонентов. - Container queries позволяют компонентам реагировать на размер их контейнера, а не viewport, заменяя JavaScript resize observers.
- Scroll-driven animations выполняются в compositor thread, обеспечивая более плавную производительность по сравнению с альтернативами на основе Intersection Observer.
- Popover API и атрибут
<details name="">предоставляют нативные, доступные всплывающие подсказки, меню и аккордеоны без пользовательских скриптов.
CSS-селектор :has(): наконец-то выбор родителя
CSS-селектор :has() решает проблему, на которую разработчики жаловались десятилетиями: стилизацию родительских элементов на основе состояния их дочерних элементов.
Раньше для переключения внешнего вида карточки при установке флажка требовались обработчики событий JavaScript. Теперь CSS справляется с этим напрямую:
.card:has(input:checked) {
border-color: blue;
}
Этот паттерн устраняет целые категории JavaScript:
- Стилизация валидации форм: стилизация контейнеров на основе состояния
:validили:invalidу полей ввода - Макеты, управляемые состоянием: изменение родительских grid-сеток в зависимости от того, пусты дочерние элементы или присутствуют
- Интерактивные компоненты: создание вкладок, аккордеонов и переключателей с использованием скрытых input и
:has()
Селектор работает во всех основных браузерах. Для поддержки старых браузеров оберните стили в @supports selector(:has(*)) и предоставьте базовый вариант отображения.
CSS Container Queries: адаптивность на уровне компонентов
Media queries реагируют на размер viewport. CSS container queries реагируют на размер контейнера компонента — это фундаментальный сдвиг в том, как мы создаём адаптивные макеты.
.card-wrapper {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
Это важно, потому что компоненты существуют в разных контекстах. Карточка в боковой панели ведёт себя иначе, чем та же карточка в основной области контента. Container queries позволяют компонентам адаптироваться к их фактически доступному пространству, а не к окну браузера.
До появления container queries для этого требовались JavaScript resize observers и ручное переключение классов. Теперь это декларативный CSS.
Scroll-Driven Animations: Intersection Observer больше не нужен
Анимации, запускаемые прокруткой, традиционно означали импорт библиотек или написание кода с Intersection Observer. CSS scroll-driven animations заменяют и то, и другое.
Два типа таймлайнов охватывают большинство случаев использования:
Scroll timelines привязывают прогресс анимации к позиции прокрутки:
@keyframes grow {
from { width: 0; }
to { width: 100%; }
}
.progress-bar {
animation: grow linear;
animation-timeline: scroll();
}
View timelines срабатывают, когда элементы входят во viewport:
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
animation: fade-in linear;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
Эти анимации выполняются в compositor thread, обеспечивая более плавную производительность, чем JavaScript-альтернативы. Всегда учитывайте предпочтения пользователей с помощью @media (prefers-reduced-motion: reduce) для отключения или упрощения анимаций.
Discover how at OpenReplay.com.
Popover API: нативные всплывающие подсказки и меню
Создание доступных поповеров исторически требовало управления ловушками фокуса, обнаружением кликов вне элемента, обработкой клавиши Escape и управлением z-index стеком. Popover API обрабатывает всё это нативно.
<button popovertarget="menu">Open Menu</button>
<div id="menu" popover>
<p>Menu content here</p>
</div>
Браузер автоматически:
- Позиционирует поповер в top layer (поверх всего остального контента)
- Закрывает его при клике вне элемента или нажатии Escape
- Корректно управляет фокусом
- Обрабатывает объявления для специальных возможностей
Стилизуйте поповеры с помощью CSS, включая анимации появления через @starting-style. Значение по умолчанию popover="auto" закрывает поповер, когда пользователи взаимодействуют с другими элементами, в то время как popover="manual" требует явного закрытия.
Нативные аккордеоны с <details name="">
Элемент <details> поддерживает аккордеоны уже много лет. Атрибут name добавляет эксклюзивное поведение — одновременно открыта только одна панель:
<details name="faq">
<summary>First question</summary>
<p>Answer content</p>
</details>
<details name="faq">
<summary>Second question</summary>
<p>Answer content</p>
</details>
Никакого JavaScript. Полная доступность с клавиатуры. Встроенная поддержка программ чтения с экрана. Стилизуйте состояние [open] и псевдоэлемент ::marker, чтобы соответствовать вашей дизайн-системе.
Прогрессивное улучшение всё ещё важно
Эти возможности имеют широкую поддержку, но прогрессивное улучшение остаётся хорошей практикой. Используйте @supports для предоставления фолбэков:
@supports not (container-type: inline-size) {
/* Запасные стили с использованием media queries */
}
Этот подход обеспечивает базовую функциональность везде, одновременно предоставляя улучшенный опыт там, где это поддерживается.
Заключение
Современный CSS без JavaScript — это не об отказе от JavaScript полностью, а о выборе правильного инструмента. Декларативные CSS-решения быстрее в реализации, проще в поддержке и часто более производительны, чем их скриптовые эквиваленты.
Начните с аудита вашего текущего JavaScript. Если он переключает классы на основе состояния, позиционирует всплывающие подсказки или отслеживает позицию прокрутки, скорее всего, CSS теперь справляется с этим. Браузер выполняет тяжёлую работу. Позвольте ему.
Часто задаваемые вопросы
Возможности, рассмотренные здесь — :has(), container queries, scroll-driven animations и Popover API — поддерживаются во всех основных браузерах, включая Chrome, Firefox, Safari и Edge по состоянию на 2025 год. Scroll-driven animations имеют самую узкую поддержку, поэтому всегда проверяйте caniuse.com для получения актуальных данных о совместимости и используйте @supports для фолбэков.
Селектор :has() обрабатывает многие сценарии стилизации на основе состояния, но имеет ограничения. Он хорошо работает для стилизации на основе состояний форм, наличия дочерних элементов или условий соседних элементов. Для сложной многошаговой логики, условного рендеринга или получения данных JavaScript остаётся необходимым. Используйте :has() для визуальных изменений состояния, а не для логики приложения.
CSS scroll-driven animations обычно превосходят JavaScript-альтернативы по производительности, потому что они выполняются в compositor thread, отдельно от основного потока. Это предотвращает layout thrashing и рывки. Однако анимация свойств, которые вызывают пересчёт макета, таких как width или height, всё ещё может вызывать проблемы с производительностью. Придерживайтесь transform и opacity для лучших результатов.
Используйте правило @supports для определения доступности возможностей и предоставления альтернативных стилей. Например, @supports not (container-type: inline-size) позволяет определить фолбэки с media query. Для фолбэков, зависящих от JavaScript, проверяйте поддержку возможностей в ваших скриптах перед инициализацией полифиллов или альтернативных реализаций.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.