Оптимизация UI-кита: стейты компонентов на CSS-переменных
При верстке UI-компонентов легко погрязнуть в рутине. Когда я создавал очередной UI-кит, я наткнулся на раздражающую закономерность: дизайнеры нарисовали для обычной кнопки примерно пять цветовых тем. И для каждой мне приходилось вручную дублировать селекторы состояний: hover, active, disabled.
CSS .base-btn--theme-secondary:hover { /* стили */ } .base-btn--theme-secondary:active { /* стили */ }
.base-btn--theme-outlined:hover { /* стили */ } .base-btn--theme-outlined:active { /* стили */ } ...и так до бесконечности для каждой темы
Конечно, можно использовать миксины в SCSS, но они лишь маскируют проблему: на выходе в бандле мы все равно получаем раздутый статичный CSS.
Тогда я пришел к декларативному подходу на CSS Custom Properties. Идея в том, чтобы описать поведение ховеров и кликов на базовом уровне один раз, привязав свойства к переменным:
CSS .base-btn { /* 1. Декларируем стейт-переменные по умолчанию */ --text-color: var(--n-n00); --background-color: var(--a-a32); /* 2. Привязываем свойства один раз */ color: var(--text-color); background-color: var(--background-color); }
/* 3. Описываем реакцию на события один раз для ВСЕХ тем */ .base-btn:hover { --text-color: var(--text-color-hover); --background-color: var(--background-color-hover); } .base-btn:active { --text-color: var(--text-color-active); --background-color: var(--background-color-active); }
Теперь, чтобы создать новую тему (например, outlined), нам больше не нужно писать селекторы событий. Мы просто переопределяем значения самих переменных в один селектор:
CSS .base-btn--theme-outlined { --text-color: var(--a-a32); --background-color: transparent;
--text-color-hover: var(--n-n00); --background-color-hover: var(--a-a30);
--text-color-active: var(--n-n00); --background-color-active: var(--a-a35); }
Где это особенно спасает: 1. Глубокая вложенность: Если внутри кнопки нужно перекрасить SVG-иконку по ховеру, вам не нужно писать .base-btn:hover .icon. Достаточно внутри .icon задать fill: var(--text-color). 2. Динамическая смена тем (Dark Mode): Достаточно поменять значения базовых токенов на корневом элементе, и все компоненты мгновенно перестроят свои ховер-состояния в рантайме.
О чем стоит помнить: Если у вашего компонента слишком много состояний (например, focus-visible, loading, error, selected), конфигурация переменных на верхнем уровне может сильно разрастись.
А как вы боретесь с дублированием стилей состояний в UI-китах? Используете рантайм-переменные или доверяете препроцессорам?