CSS вытесняет JavaScript: современные CSS-паттерны без JS
Обзор возможностей · Июнь 2026

CSS вытесняет JavaScript:
современные CSS-паттерны без JS

Когда Кевин Пауэлл вышел на сцену CSS Day 2026 в Амстердаме сегодня, он показал нечто примечательное: у CSS появились функции, запросы и выражения, которые ещё год назад были исключительной территорией JavaScript. Граница между CSS и JS размывается — и это хорошо.

Олег Максимов 12 июня 2026 15 мин чтения CSS Day 2026, Амстердам

Сдвиг: от императивного к декларативному

Последние десять лет веб-разработка следовала простому правилу: HTML — для структуры, CSS — для представления, JavaScript — для поведения. Но по мере усложнения веб-приложений JavaScript впитывал всё больше CSS-территории — адаптивный дизайн, переключение тем, скролл-эффекты и даже решения по расположению элементов.

Этот тренд разворачивается. CSS возвращает себе утраченные позиции — с инструментами, которые производительнее, декларативнее и надёжнее JavaScript-обходных путей, которые они заменяют.

Доклад Кевина Пауэлла на CSS Day 2026 продемонстрировал три возможности, олицетворяющие этот сдвиг: CSS if() для встроенных условных значений, продвинутый attr() для чтения HTML-данных в CSS и style queries (@container style()) для стилизации на основе состояния компонента. Вместе они устраняют целые категории JavaScript-шаблонов.

Разберём каждую возможность с примерами кода и посмотрим, что они заменяют.

CSS 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. Теперь браузер делает всё нативно.

Style Queries — состояние компонента без JavaScript

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

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. Результат: более плавные анимации, меньше работы на главном потоке, проще код компонентов.

До и После: JS vs CSS бок о бок

Сравним три типичных UI-паттерна: JavaScript-подход (сегодня) против CSS-подхода (современный).

1. Компонент вкладок (tabs)

JavaScript-подход

tabs.forEach(tab => {
  tab.addEventListener('click', () => {
    panels.forEach(p => p.classList.remove('active'));
    tab.parentElement.dataset.active = tab.dataset.tab;
  });
});

+ переключение классов + слушатели событий. ~20 строк.

CSS-подход

/* Style query проверяет data-active */
@container style(--active: tab-2) {
  #tab-2 { display: block; }
}

0 строк JS. HTML управляет состоянием через атрибуты.

2. Переключение темы

JavaScript-подход

document.documentElement
  .style.setProperty(
    '--bg', isDark
      ? '#1a1a2e' : '#ffffff'
  );
// + ещё 10 свойств...

+ логика переключения + localStorage. ~40 строк.

CSS-подход

@container style(--theme: dark) {
  :root {
    --bg: #1a1a2e;
    --text: #e4e4e7;
    --border: #334155;
  }
}

Декларативно. --theme управляет всем.

3. Адаптивная сетка

JavaScript-подход

const cols = window.innerWidth > 1024
  ? 4 : window.innerWidth > 640
  ? 2 : 1;
grid.style.gridTemplateColumns =
  `repeat(${cols}, 1fr)`;

Слушатели resize + пересчёт. Debounce, чтобы не дёргать.

CSS-подход

.grid {
  grid-template-columns:
    attr(data-cols number, 3) 1fr;
}

@media (width < 640px) {
  .grid { --cols: 1; }
}

Чистый CSS. Браузер управляет адаптивностью нативно.

Арсенал 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-компонентах.

Anchor Positioning — замена JS-библиотек позиционирования

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;
}

Scroll-Driven Animations

Анимации, привязанные к скроллу — без 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 вбирает в себя презентационный JavaScript — императивный код, управляющий визуальным состоянием, позиционированием и анимациями. CSS всегда был правильным инструментом для этих задач; мы просто ждали, пока CSS догонит потребности.

JavaScript остаётся правильным выбором для:

Цель не «ноль JavaScript». Цель — соразмерный JavaScript: использовать JS там, где он добавляет ценность, и CSS там, где он справляется лучше.

Стратегия миграции: начните сегодня

Не нужно ждать полной поддержки браузеров. Три шага для старта:

1. Аудит переключения классов

Каждый раз, когда вы пишете element.classList.toggle('active'), спросите: «Может ли кастомное свойство сделать это вместо меня?» Замените состояния на основе классов на --state и let style queries возьмут на себя визуальные последствия.

2. Используйте @supports()

.accordion-panel {
  display: none; /* JS fallback */
}

@supports (container-type: style) {
  .accordion-panel {
    display: revert;
  }

  @container style(--open: true) {
    .accordion-panel {
      display: block;
    }
  }
}

3. Заменяйте одну JS-библиотеку за раз

Начните с самого простого: уберите Popper.js/Floating UI в пользу CSS Anchor Positioning. Затем замените scroll-библиотеки на scroll-driven animations. Потом примитесь за аккордеоны, вкладки и переключение темы через style queries и if().

Каждая замена убирает JavaScript-зависимость, уменьшает размер бандла и устраняет категорию рантайм-багов. Совокупный эффект впечатляет.

FAQ

Может ли CSS if() заменить JavaScript-условия в стилях?
CSS if() предоставляет встроенные условные значения для свойств — как тернарный оператор в JS, но ограниченный значениями CSS. Работает с кастомными свойствами и style queries. Не заменяет сложную JS-логику, но устраняет необходимость в переключении классов через JavaScript для простых условных стилей.
Что может новый CSS attr() с типами?
Типизированный attr() возвращает не только строки, но и числа, длины, цвета, углы и другие типы. Это позволяет читать HTML-data-атрибуты напрямую в CSS-свойствах — width, height, padding, color, grid-template-columns — без JavaScript как прослойки.
Что такое CSS style queries?
Style queries (@container style()) позволяют запрашивать вычисленные значения CSS-свойств на контейнере. Например, @container style(--theme: dark) { .card { background: #1a1a2e; } }. Это даёт возможность управлять стилями на основе состояния компонента полностью на CSS, без переключения классов через JavaScript.
Сколько JavaScript реально можно заменить на CSS в 2026 году?
В типичном UI-приложении CSS может заменить 40-70% презентационного JavaScript — переключение классов, стили на основе состояния, адаптивные макеты, компоненты вкладок/аккордеонов, позиционирование тултипов и скролл-эффекты. Бизнес-логика, загрузка данных, валидация форм и сложные интеракции остаются за JavaScript.
Какие браузеры поддерживают CSS if(), style queries и attr() с типами?
Style queries работают в Chrome 111+, Firefox 110+ и Safari 18+. CSS if() пока на стадии спецификации (CSS Values 5) — Chrome Canary поддерживает экспериментально за флагом. Типизированный attr() доступен в Chrome 128+ для типов length и number. Используйте @supports() для прогрессивного улучшения и graceful fallback.
То, что CSS заменяет JavaScript — это хорошо?
Да — это признак взросления веб-платформы. Декларативные CSS-решения производительнее, доступнее и менее подвержены ошибкам, чем императивные JavaScript-альтернативы. Меньше JS — меньше бандлы, быстрее рендеринг, меньше багов. Но CSS лучше всего справляется с презентационной логикой; бизнес-логика и интерактивность остаются за JavaScript.
Как начать миграцию с JavaScript на CSS-паттерны?
Начните с простого: замените переключение классов через JS на кастомные свойства; замените JS-аккордеоны и вкладки на style queries; используйте has() вместо JS для стилизации родителя; внедрите anchor positioning вместо Popper.js; замените scroll-эффекты на scroll-driven animations. Каждая замена уменьшает бандл и устраняет категорию рантайм-багов.

Хотите построить более лёгкое веб-приложение?

Современные CSS-паттерны позволяют создавать UI, которые быстрее, меньше и проще в поддержке. Если вы планируете веб-проект и хотите архитектуру, минимизирующую накладные расходы JavaScript при максимальной производительности — я буду рад помочь.

Я — full-stack веб-разработчик, живу в Минске, работаю по всему миру. С 20+ лет опыта в React, Vue, Angular, Node.js и современных CSS-архитектурах я спроектирую и построю ваш проект, используя правильные инструменты — от серверных компонентов до CSS-нативной интерактивности. Обсудим ваш проект.

Контакты

Обсудим ваш проект

Расскажите о вашем проекте — я порекомендую лучшую архитектуру и подготовлю предварительную оценку. Бесплатно.