Skip to content

Введение

ECSS (Extended CSS) — это надмножество CSS, которое компилируется на этапе сборки. Оно позволяет описывать состояния и варианты компонента прямо в файле стилей, не дублируя логику в JavaScript, и при этом даёт полную типизацию в TypeScript и минимальный рантайм.

Что такое ECSS?

Любой валидный CSS является валидным ECSS. Поверх привычного синтаксиса ECSS добавляет несколько директив, которые превращают .ecss-файл в типизированный компонент:

  • @block — именованный компонент стилей;
  • @param — параметр, управляющий тем, какие правила применяются;
  • @if / @elseif / @else — условные стили на основе параметров;
  • @enum, @const, @element, @import, @external — перечисления, константы, вложенные элементы и работа с несколькими файлами.

Компилятор превращает .ecss-файл в обычный статический CSS плюс типизированный модуль, который импортируется в код приложения.

Какую проблему решает ECSS

Обычно логика состояний компонента размазана между двумя местами: классы объявлены в CSS, а решение «какой класс применить» живёт в JavaScript. Каждый новый вариант требует правок и там, и там, а связь между значением пропа и классом ничем не гарантирована.

ECSS переносит эту логику в стили. Компонент не знает ни о каких классах — он лишь передаёт параметры.

Как это выглядит

ecss
/* Button.ecss */
@enum Variant {
  values: "primary", "danger", "ghost";
}

@block Button {
  @param --variant Variant;
  @param --disabled? boolean;

  display: inline-flex;
  padding: 8px 16px;
  border-radius: 6px;
  cursor: pointer;

  @if (--variant == "primary") {
    background: #646cff;
    color: #fff;
  }

  @if (--disabled) {
    opacity: 0.4;
    cursor: not-allowed;
  }
}

Импортируем сгенерированный компонент и передаём параметры — сборка className и подстановка нужных стилей происходят автоматически:

tsx
import { EButton } from './Button.ecss';

<EButton as="button" params={{ variant: 'primary' }}>
  Кнопка
</EButton>;

TypeScript знает допустимые значения variant из объявления @enum — передать несуществующий вариант не получится.

Ключевые особенности

  • Надмножество CSS. Знакомый синтаксис; добавляете только то, что нужно.
  • Состояния без JS. Параметры (@param) и условные стили (@if) описываются в .ecss-файле, а не в компоненте.
  • Полная типизация. Для каждого импорта *.ecss генерируются точные типы — автодополнение и проверка типов работают из коробки.
  • Любой фреймворк. Адаптеры генерируют компоненты для React, Vue, Svelte и SolidJS; есть и адаптер для чистого DOM.
  • Сборка, а не рантайм. В браузер попадает статический CSS — нет runtime-оверхеда, работает с SSR без дополнительной настройки.
  • Минимальный рантайм. В бандл добавляется лишь крошечный хелпер для сборки классов и CSS-переменных.
  • Поддержка в редакторе. Расширение для VS Code даёт подсветку синтаксиса, диагностику ошибок и hover-подсказки.

Как это работает

  1. Вы пишете .ecss-файлы с блоками, параметрами и условиями.
  2. Компилятор (@ecss/compiler) превращает их в статический CSS и типизированный JS-модуль, а адаптер — в компоненты для вашего фреймворка.
  3. Плагин сборщика (@ecss/vite-plugin) подключает всё это в проект, а конфигурация (@ecss/config) общая и не привязана к конкретному сборщику.

Что дальше?