Когда Кевин Пауэлл вышел на сцену CSS Day 2026 в Амстердаме сегодня, он показал нечто примечательное: у CSS появились функции, запросы и выражения, которые ещё год назад были исключительной территорией JavaScript. Граница между CSS и JS размывается — и это хорошо.
Последние десять лет веб-разработка следовала простому правилу: HTML — для структуры, CSS — для представления, JavaScript — для поведения. Но по мере усложнения веб-приложений JavaScript впитывал всё больше CSS-территории — адаптивный дизайн, переключение тем, скролл-эффекты и даже решения по расположению элементов.
Этот тренд разворачивается. CSS возвращает себе утраченные позиции — с инструментами, которые производительнее, декларативнее и надёжнее JavaScript-обходных путей, которые они заменяют.
Доклад Кевина Пауэлла на CSS Day 2026 продемонстрировал три возможности,
олицетворяющие этот сдвиг: CSS if() для
встроенных условных значений, продвинутый attr()
для чтения HTML-данных в CSS и style queries
(@container style()) для стилизации на основе состояния
компонента. Вместе они устраняют целые категории JavaScript-шаблонов.
Разберём каждую возможность с примерами кода и посмотрим, что они заменяют.
if() — встроенные условные значения
Функция if() из спецификации CSS Values Module Level 5
добавляет условную логику прямо в значения свойств. Синтаксис напоминает
тернарный оператор JavaScript:
/* Базовый условный padding */
.element {
padding: if(style(--compact), 0.5rem, 1.5rem);
}
/* Несколько условий */
.element {
font-size: if(
style(--size: small), 0.875rem,
style(--size: large), 1.25rem,
1rem
);
}
if() вычисляет условие — обычно style-запрос к кастомному
свойству — и возвращает одно из двух значений. Чистый CSS. Никакого
JavaScript. Никакого переключения классов.
Вспомните, сколько раз вы писали:
// JavaScript-версия — три строки для одной строчки стиля
if (isCompact) {
element.style.padding = '0.5rem';
} else {
element.style.padding = '1.5rem';
}
Когнитивная нагрузка, код в разных файлах. if() держит условие
там, где ему место — в CSS-правиле.
if() естественно сочетается с calc(), clamp() и другими
CSS-функциями:
.card {
/* Композиция if() с другими функциями */
width: calc(100% - if(style(--sidebar: true), 320px, 0px));
/* В сокращённых свойствах */
margin: if(style(--compact), 0.5rem 1rem, 1.5rem 2rem);
}
/* Работает с любыми свойствами */
.button {
--bg-light: #f0f4ff;
--bg-dark: #1e293b;
background: if(style(--theme: dark), var(--bg-dark), var(--bg-light));
color: if(style(--theme: dark), #e2e8f0, #1e293b);
border-color: if(style(--theme: dark), #334155, #cbd5e1);
}
if() не заменяет JavaScript-условия для бизнес-логики.
Он заменяет их для стилевых решений — где они всегда и должны
были быть.
attr() — HTML-данные в CSS
Функция attr() существует в CSS десятилетиями, но с серьёзным
ограничением: она работала только в свойстве content на
псевдоэлементах и всегда возвращала строку. В 2026 году это меняется.
Новый типизированный attr() принимает параметр типа и может
использоваться в любых CSS-свойствах:
/* HTML */
<div data-width="300" data-color="oklch(0.5 0.2 240)">
Этот div читает стили из HTML-атрибутов
</div>
/* CSS — attr() возвращает типизированные значения */
div {
width: attr(data-width number, 100%) px;
background: oklch(from attr(data-color color) l c h / 0.2);
padding: attr(data-padding length, 1rem);
}
/* Колонки из HTML-атрибута */
.grid {
grid-template-columns: attr(data-cols number, 3) 1fr;
}
Параметр типа открывает CSS-свойства, ранее недоступные из HTML-атрибутов:
Это устраняет паттерн «прочитать data-атрибут в JavaScript, распарсить, применить как inline-стиль». CSS-движок делает это напрямую — быстрее и без JS-накладных расходов.
/* HTML — значение в data-атрибуте */
<progress-bar data-value="73" data-max="100"></progress-bar>
/* CSS — без единой строчки JS */
progress-bar {
display: block;
height: 8px;
background: #e2e8f0;
border-radius: 4px;
overflow: hidden;
}
progress-bar::before {
content: '';
display: block;
height: 100%;
width: calc(attr(data-value number) / attr(data-max number) * 100%);
background: linear-gradient(90deg, #3b82f6, #6366f1);
border-radius: 4px;
transition: width 0.3s ease;
}
Раньше для этого требовался JavaScript: прочитать data-value,
вычислить процент, установить element.style.width. Теперь
браузер делает всё нативно.
CSS-контейнерные запросы были прорывом — запрос размера элемента вместо
области просмотра. Но размер — не единственная важная метрика. Встречайте
style queries: @container style().
Style queries проверяют вычисленные значения CSS-свойств на контейнере, не его размеры. Это даёт логику состояния компонента полностью на CSS:
/* Определяем контейнер */
.card-container {
container-type: inline-size;
}
/* Style query — проверка темы */
@container style(--theme: dark) {
.card {
background: #1a1a2e;
color: #e4e4e7;
border-color: #334155;
}
}
/* Style query — проверка состояния */
@container style(--state: error) {
.card {
border-color: #ef4444;
background: #fef2f2;
}
}
@container style(--state: success) {
.card {
border-color: #22c55e;
background: #f0fdf4;
}
}
Style queries работают с любыми CSS-свойствами, не только
кастомными. Можно запрашивать display, position,
flex-direction:
/* Адаптация потомков к режиму контейнера */
@container style(flex-direction: column) {
.item { margin-bottom: 1rem; }
}
@container style(flex-direction: row) {
.item { margin-right: 1rem; }
}
Style queries устраняют самый распространённый JS-паттерн в UI-компонентах: переключение классов по состоянию. Каждый React/Vue/Angular-компонент, делающий что-то вроде:
// Переключение классов — это может делать CSS
function Card({ theme, state }) {
return (
<div className={`card ${theme} ${state}`}>...</div>
);
}
Style queries позволяют CSS-движку браузера обрабатывать переходы состояний мгновенно, минуя event loop JavaScript. Результат: более плавные анимации, меньше работы на главном потоке, проще код компонентов.
Сравним три типичных UI-паттерна: JavaScript-подход (сегодня) против CSS-подхода (современный).
tabs.forEach(tab => {
tab.addEventListener('click', () => {
panels.forEach(p => p.classList.remove('active'));
tab.parentElement.dataset.active = tab.dataset.tab;
});
});
+ переключение классов + слушатели событий. ~20 строк.
/* Style query проверяет data-active */
@container style(--active: tab-2) {
#tab-2 { display: block; }
}
0 строк JS. HTML управляет состоянием через атрибуты.
document.documentElement
.style.setProperty(
'--bg', isDark
? '#1a1a2e' : '#ffffff'
);
// + ещё 10 свойств...
+ логика переключения + localStorage. ~40 строк.
@container style(--theme: dark) {
:root {
--bg: #1a1a2e;
--text: #e4e4e7;
--border: #334155;
}
}
Декларативно. --theme управляет всем.
const cols = window.innerWidth > 1024
? 4 : window.innerWidth > 640
? 2 : 1;
grid.style.gridTemplateColumns =
`repeat(${cols}, 1fr)`;
Слушатели resize + пересчёт. Debounce, чтобы не дёргать.
.grid {
grid-template-columns:
attr(data-cols number, 3) 1fr;
}
@media (width < 640px) {
.grid { --cols: 1; }
}
Чистый CSS. Браузер управляет адаптивностью нативно.
Перечисленные возможности — главные новинки, но они присоединяются к арсеналу CSS, который последние годы последовательно отвоёвывает территорию у JavaScript.
:has() — родительский селектор
CSS :has() позволяет стилизовать элемент по его потомкам —
тот самый «родительский селектор», которого ждали десятилетиями.
/* Стилизация карточки, когда внутри отмечен чекбокс */
.card:has(input[type="checkbox"]:checked) {
border-color: var(--accent);
background: rgba(15, 118, 110, 0.05);
}
/* Стилизация группы с ошибкой */
.form-group:has(:invalid) .error-message {
display: block;
}
Подробнее о контейнерных запросах я писал в руководстве по CSS Container Queries.
Сочетание :has() и style queries устраняет большинство
JavaScript-паттернов «если-то-иначе» в UI-компонентах.
CSS Anchor Positioning позволяет позиционировать элемент относительно другого без JavaScript. Тулы, поповеры, выпадающие меню — без Popper.js или Floating UI:
.tooltip {
position: absolute;
position-anchor: --trigger;
top: anchor(--trigger bottom);
left: anchor(--trigger center);
translate: -50% 8px;
}
Анимации, привязанные к скроллу — без IntersectionObserver, без слушателей прокрутки, без requestAnimationFrame:
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
animation: fade-in linear forwards;
animation-timeline: view();
animation-range: entry 0% entry 100%;
}
Это заменяет не только JavaScript, но и целые библиотеки скролл-анимаций.
CSS не заменяет JavaScript. CSS вбирает в себя презентационный JavaScript — императивный код, управляющий визуальным состоянием, позиционированием и анимациями. CSS всегда был правильным инструментом для этих задач; мы просто ждали, пока CSS догонит потребности.
JavaScript остаётся правильным выбором для:
Цель не «ноль JavaScript». Цель — соразмерный JavaScript: использовать JS там, где он добавляет ценность, и CSS там, где он справляется лучше.
Не нужно ждать полной поддержки браузеров. Три шага для старта:
Каждый раз, когда вы пишете element.classList.toggle('active'),
спросите: «Может ли кастомное свойство сделать это вместо меня?» Замените
состояния на основе классов на --state и let style queries
возьмут на себя визуальные последствия.
@supports().accordion-panel {
display: none; /* JS fallback */
}
@supports (container-type: style) {
.accordion-panel {
display: revert;
}
@container style(--open: true) {
.accordion-panel {
display: block;
}
}
}
Начните с самого простого: уберите Popper.js/Floating UI в пользу
CSS Anchor Positioning.
Затем замените scroll-библиотеки на scroll-driven animations.
Потом примитесь за аккордеоны, вкладки и переключение темы через
style queries и if().
Каждая замена убирает JavaScript-зависимость, уменьшает размер бандла и устраняет категорию рантайм-багов. Совокупный эффект впечатляет.
Современные CSS-паттерны позволяют создавать UI, которые быстрее, меньше и проще в поддержке. Если вы планируете веб-проект и хотите архитектуру, минимизирующую накладные расходы JavaScript при максимальной производительности — я буду рад помочь.
Я — full-stack веб-разработчик, живу в Минске, работаю по всему миру. С 20+ лет опыта в React, Vue, Angular, Node.js и современных CSS-архитектурах я спроектирую и построю ваш проект, используя правильные инструменты — от серверных компонентов до CSS-нативной интерактивности. Обсудим ваш проект.
Расскажите о вашем проекте — я порекомендую лучшую архитектуру и подготовлю предварительную оценку. Бесплатно.