CSS-in-TS
Функции StyleSheet maker могут описывать генерируемые стили с помощью специальных типов, так что при их использовании TypeScript подскажет доступные CSS-селекторы. Эта возможность использует дженерики TypeScript, скрывая реализацию стилей за внешним интерфейсом.
Описание стилей
Первый шаг в разработке стилей с помощью EffCSS - это зафиксировать предоставляемую функциональность в виде типа TypeScript. Начиная с версии v4.6.0 нет ограничения на уровни вложенности объекта, при этом на любом уровне вы можете определять свойства со строковым или числовым значением:
export type TCustomMaker = {
/**
* Width utility
*/
w: 's' | 'm' | 'l';
/**
* Logo
*/
logo: {
/**
* Spin animation
*/
spin: '';
/**
* Logo scale
*/
scale: 1 | 2;
};
/**
* Body
*/
body: {
/**
* Padding size
*/
p: 's' | 'm' | 'l';
};
/**
* Footer
*/
footer: {
/**
* Is footer hidden
*/
hidden: '';
};
/**
* Panel block
*/
panel: {
/**
* Is panel modal
*/
modal: '';
/**
* Max panel width
*/
max: 'vw' | 'parent';
/**
* Close button
*/
closeBtn: Record<string, never>;
}
};Для всех уровней рекомендуется использовать семантические ключи, написаные в стиле lowerCamelCase.
Реализация стилей
Второй шаг в разработке стилей с помощью EffCSS - это реализовать описанную функциональность в рамках функции StyleSheet maker. Для генерации уникальных селекторов с префиксом таблицы стилей в EffCSS используется утилита select. Эта утилита также проверяет допустимость реализуемых CSS-селекторов.
Каждый селектор образуется путем соединения с помощью точки пути до нужного свойства и добавления знака : перед его значением, если оно не является объектом:
import { TStyleSheetMaker } from 'effcss';
export type TCustomMaker = {...};
const maker: TStyleSheetMaker = ({
select,
}) => {
const selector = select<TCustomMaker>;
return {
[selector('logo')]: {
// ...
},
[selector('logo.scale:1')]: {
// ...
},
[selector('logo.spin:')]: {
// ...
},
[selector('panel.closeBtn')]: {
// ...
}
}
};
export default maker;Использование стилей
Чтобы получить резолвер селекторов, вам нужно передать соответствующую функцию StyleSheet maker в метод use объекта Style provider. У резолвера есть два метода - list и obj, с их помощью и выводятся HTML-атрибуты с нужными селекторами:
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (use: IStyleProvider['use']) => {
const [css] = use(customStyle);
return {
firstElemAttrs: css.obj<TCustomMaker>({
w: 's',
panel: {
max: 'parent'
}
}), // {[attributeName]: 'selectors_string'}
secondElemAttrs: css.list<TCustomMaker>('logo.spin:', 'body.p:m') // {[attributeName]: 'selectors_string'}
};
};Режимы генерации атрибутов
Компонент Style provider может влиять на генерацию селекторов с помощью 2 атрибутов:
mode- может иметь значениеa(используетdata-*-атрибуты) иc(использует атрибутclass),min- булев атрибут, который позволяет минифицировать селекторы.
Генерация CSS-классов более предсказуема, а генерация data-атрибутов позволяет визуально отделить селекторы разных таблиц. Используйте то, что вам больше по душе.
Минификация сохраняет уникальный префикс в составе селектора, поэтому стили разных таблиц останутся изолированными, при этом длина селекторов существенно сократится.
Если используется режим генерации a и используемый фреймворк поддерживает такой синтаксис, полученные атрибуты можно передать в верстку напрямую:
<div {...firstElemAttrs}>...</div>Если используется режим генерации с, вы можете взять классы из объекта и передать в верстку:
<div className={firstElemAttrs.class}>...</div>Явная генерация селекторов классов
Начиная с версии 4.10.0, вы можете напрямую получать нужные селекторы классов CSS с помощью утилиты cx. Эта утилита игнорирует атрибут mode у компоненат Style provider и возвращает строку с именами классов:
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
return {
firstElemAttrs: provider.cx<TCustomMaker>(customStyle, {
w: 's',
panel: {
max: 'parent'
}
}),
secondElemAttrs: provider.cx<TCustomMaker>(customStyle, ['logo.spin:', 'body.p:m'])
};
};Явная генерация селекторов data-атрибутов
Начиная с версии 4.10.0, вы можете напрямую получать нужные селекторы data-атрибутов с помощью утилиты dx. Эта утилита игнорирует атрибут mode у компоненат Style provider и возвращает объект со значениями атрибута:
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
return {
firstElemAttrs: provider.dx<TCustomMaker>(customStyle, {
w: 's',
panel: {
max: 'parent'
}
}),
secondElemAttrs: provider.dx<TCustomMaker>(customStyle, ['logo.spin:', 'body.p:m'])
};
};WARNING
Каждая функция StyleSheet maker создает только одну таблицу стилей, поэтому вам нужно использовать либо утилиту cx, либо dx, но не обе одновременно.
Польза
Описанный подход позволяет отделить контракт от реализации - при разработке вы изначально знаете, какие CSS-селекторы должны предоставить, а любой сторонний разработчик сможет импортировать ваш тип TCustomMaker и получить нужные стили, не заглядывая в вашу функцию StyleSheet maker. Учитывая, что в при сборке JS-файлы обычно подвергаются минификации, предложенный подход здорово экономит время.
Кроме того EffCSS генерирует для каждой таблицы стилей свои уникальные селекторы, что исключает риск их переопределения.
Таким образом, EffCSS позволяет шагнуть дальше обычного создания CSS, приближаясь к роли CSS-in-TS.