Композиция и темизация компонентов
Что это такое
Композиция — это сборка крупных компонентов из мелких, при которой ни один из них не знает о других больше необходимого. Темизация — смена внешнего вида компонента снаружи — цвета, отступы, плотность, — без правки самого компонента и без его дублирования. И то и другое превращает папку компонентов в систему, из которой действительно можно собрать целый продукт.
Почему это важно
Библиотека компонентов, которую нельзя компоновать, порождает новый специальный компонент на каждый экран, и расхождение, которое вы устранили, возвращается — теперь на уровне экрана. Библиотека, которую нельзя темизировать, порождает либо форк под каждый бренд, либо свойство под каждый цвет, — а когда получилось и то и другое, одна команда выпускает из одних и тех же компонентов маркетинговый сайт, приложение и вид под бренд партнёра. От этого же зависит, насколько дорого обойдётся следующее изменение дизайна: со слоем темы это правка токена, без него — миграция.
Ключевые идеи
Компонуйте вложением, а не настройкой
Toolbar должен располагать то, что ему дали, а не принимать список элементов и режим отрисовки. Вложение держит задачу каждого компонента маленькой и позволяет вызывающему выразить расположение, которое автор не предусмотрел.
<Card>
<Card.Header>
<Avatar user={user} />
<span>{user.name}</span>
</Card.Header>
<Card.Body>{bio}</Card.Body>
</Card>
Делите контракт стилей через пользовательские свойства
Пользовательские свойства наследуются, поэтому обёртка может задать их всему внутри без селектора на каждый компонент. Этот один механизм покрывает плотность, радиус, цвет и отступы, а поверхность темизации остаётся явной и маленькой.
.compact {
--control-pad: 0.25rem 0.5rem;
--control-radius: 0.25rem;
}
.button { padding: var(--control-pad); border-radius: var(--control-radius); }
Темизируйте токенами, а не переопределениями
Тема — набор значений, а переопределение — правило, которое побеждает компонент снаружи. Переопределения множатся и побеждают специфичностью, поэтому следующей теме нужен селектор длиннее. Токены переворачивают это: компонент читает значение, а тема его поставляет, и любое число тем сосуществует, не соревнуясь.
Держите поверхность темизации документированной и версионированной
Всё, что потребитель может задать, — публичный API. Запишите его, назовите единообразно и считайте, что переименование ломает совместимость. Библиотеки компонентов, которые об этом забывают, в итоге получают два класса для одной цели, потому что переименовать первый было слишком рискованно.
Дайте вызывающему расширять, а не форкать
Откройте слот в том месте, где ожидается вариация, — нижний колонтитул, область действий, иконку, — и вызывающий расширит компонент на месте. Любая вариация, которой нужна копия всего компонента, означает недостающий слот, а не новый компонент.
Практика
Соберите компактную тему без правки компонентов
Возьмите два-три существующих компонента, которые делят значения отступов и радиуса. Вынесите эти значения в пользовательские свойства и добавьте класс-обёртку, который задаёт их в более плотном масштабе.
Готово, когда: внутри обёртки компоненты выглядят компактно, снаружи — без изменений, и ни один файл компонента не был отредактирован.
Расширьте компонент слотом
Выберите компонент, который вызывающие однажды скопировали. Добавьте слот, который покрыл бы разницу, и переведите одну копию на его использование.
Готово, когда: копия удалена, оригинал правильно рисует оба варианта, а имя слота задокументировано.
Частые ошибки
- Темизация переопределением селекторов компонента — специфичность растёт с каждой темой, и компонент нельзя отрефакторить; исправить: откройте значения пользовательскими свойствами и позвольте теме их задавать.
- Свойство на каждую новую вариацию — API растёт без предела, а недопустимые сочетания множатся; исправить: добавьте слот или токен и дайте вызывающему менять вариацию.
- Протечка темы в компонент — компонент теперь знает об одном бренде и не может обслуживать второй; исправить: пусть компонент читает только свои свойства и их запасные значения.
- Недокументированная поверхность темизации — потребители угадывают имена свойств и лезут во внутренности; исправить: документируйте каждое публичное свойство и считайте изменения версионируемыми.
- Форк компонента ради одного экрана — исправление доходит только до одной копии, и копии расходятся; исправить: расширьте оригинал слотом вместо копирования.
Что читать дальше
- Проектирование API компонента (02-frontend/12-ui-components/01-designing-a-component-api) — свойства и значения по умолчанию, которые темизирует этот урок; перечитайте его, прежде чем добавлять новую вариацию.
- Современные возможности CSS (02-frontend/05-css/04-modern-css) — пользовательские свойства и поведение каскада, на котором держится подход с токенами.
- Дизайн-токены (03-design-ux/41-design-tokens) — как называть и упорядочивать значения, которые задаёт тема.