TypeScriptにおけるCSS
StyleSheet maker関数は、特殊な型を使用して生成されるスタイルを記述できるため、これらの関数を使用すると、TypeScriptは利用可能なCSSセレクタをプロンプトで表示します。この機能はTypeScriptのジェネリクスを利用しており、スタイルの実装を外部インターフェースの背後に隠蔽しています。
スタイルの説明
EffCSS を使用してスタイルを開発する最初のステップは、提供される機能を TypeScript 型として定義することです。バージョン v4.6.0 以降、オブジェクトのネストレベルに制限はなく、どのレベルでも文字列または数値のプロパティを定義できます。
すべてのレベルにおいて、lowerCamelCase スタイルで記述された意味のある名前を使用することをお勧めします。
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>;
}
};スタイルの実装
EffCSS を用いたスタイル開発の第2ステップは、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;バージョン4.15.0以降、TStyleSheetMaker型は汎用型となり、パブリックセレクタの型をパラメータとして受け取るようになったため、このパラメータをselectユーティリティに渡す必要はありません。
import { TStyleSheetMaker } from 'effcss';
export type TCustomMaker = {...};
const maker: TStyleSheetMaker<TCustomMaker> = ({
select,
}) => {
return {
[select('logo')]: {
// ...
},
[select('logo.scale:1')]: {
// ...
},
[select('logo.spin:')]: {
// ...
},
[select('panel.closeBtn')]: {
// ...
}
}
};
export default maker;スタイルの使用方法
セレクタリゾルバーを取得するには、対応するStyleSheet maker関数をStyle providerオブジェクトのuseメソッドに渡す必要があります。リゾルバーにはlistとobjという2つのメソッドがあり、これらは必要なセレクタを持つ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属性を使用)の2つの値を指定できます。バージョン4.11.0以降、modeは非推奨となり、次期メジャーバージョンで削除されます。データ属性またはクラス名としてセレクタを明示的に生成するには、dxメソッドとcxメソッドを使用してください。minは、BEMセレクタを最小化するためのブール値属性です。
CSSクラス生成はより予測可能であり、データ属性生成は異なるスタイルシートを視覚的に区別できます。お好みに合わせて使用してください。
最小化ではセレクタに固有のプレフィックスが保持されるため、異なるテーブルのスタイルは分離されたままになり、セレクタの長さは大幅に短縮されます。
a生成モードが使用され、使用するフレームワークがこの構文をサポートしている場合、生成された属性をレイアウトに直接渡すことができます。
<div {...firstElemAttrs}>...</div>c生成モードを使用する場合、オブジェクトからクラスを取得し、レイアウトに渡すことができます。
<div className={firstElemAttrs.class}>...</div>クラス名の明示的な生成
バージョン4.10.0以降では、cxユーティリティを使用して必要なCSSクラスセレクタを直接取得できます。このユーティリティはStyle providerのmode属性を無視し、クラス名を含む文字列を返します。
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
const firstElemCls = provider.cx<TCustomMaker>(customStyle, {
w: 's',
panel: {
max: 'parent'
}
});
const secondElemCls = provider.cx<TCustomMaker>(customStyle, ['logo.spin:', 'body.p:m']);
return {
firstElemCls,
secondElemCls,
// starting from version 4.11.0 you can combine many selectors with `join`
combinedCls: provider.cx.join(firstElemCls, secondElemCls)
};
};バージョン4.15.0以降、TStyleSheetMaker型は汎用型となり、パブリックセレクタの型をパラメータとして受け取るため、このパラメータをcxメソッドに渡す必要はありません。
import { IStyleProvider } from 'effcss';
import { default as customStyle } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
const firstElemCls = provider.cx(customStyle, {
w: 's',
panel: {
max: 'parent'
}
});
const secondElemCls = provider.cx(customStyle, ['logo.spin:', 'body.p:m']);
return {
firstElemCls,
secondElemCls,
// starting from version 4.11.0 you can combine many selectors with `join`
combinedCls: provider.cx.join(firstElemCls, secondElemCls)
};
};データ属性の明示的な生成
バージョン4.10.0以降では、dxユーティリティを使用して必要なCSSデータ属性セレクタを直接取得できます。このユーティリティはStyle providerのmode属性を無視し、データ属性を含むオブジェクトを返します。
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
const firstElemAttrs = provider.dx<TCustomMaker>(customStyle, {
w: 's',
panel: {
max: 'parent'
}
});
const secondElemAttrs = provider.dx<TCustomMaker>(customStyle, ['logo.spin:', 'body.p:m']);
return {
firstElemAttrs,
secondElemAttrs,
// starting from version 4.11.0 you can combine many selectors with `join`
combinedAttrs: provider.dx.join(firstElemAttrs, secondElemAttrs)
};
};バージョン4.15.0以降、TStyleSheetMaker型は汎用型となり、パブリックセレクタの型をパラメータとして受け取るため、このパラメータをdxメソッドに渡す必要はありません。
import { IStyleProvider } from 'effcss';
import { default as customStyle } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
const firstElemAttrs = provider.dx(customStyle, {
w: 's',
panel: {
max: 'parent'
}
});
const secondElemAttrs = provider.dx(customStyle, ['logo.spin:', 'body.p:m']);
return {
firstElemAttrs,
secondElemAttrs,
// starting from version 4.11.0 you can combine many selectors with `join`
combinedAttrs: provider.dx.join(firstElemAttrs, secondElemAttrs)
};
};WARNING
各スタイルシート作成ツールは1つのスタイルシートしか作成しないため、cxユーティリティまたはdxユーティリティのいずれか一方を、どちらか一方の作成ツールと組み合わせて使用する必要があります。両方を同時に使用する必要はありません。
利点
このアプローチでは、契約と実装を分離できます。開発段階で、どのCSSセレクタを提供すべきかを事前に把握できるため、サードパーティの開発者はTCustomMaker型をインポートするだけで、StyleSheet maker関数を参照することなく必要なスタイルを取得できます。JavaScriptファイルは通常、アセンブリ時にミニファイされるため、このアプローチは大幅な時間短縮につながります。
さらに、EffCSSは各スタイルシートごとに固有のセレクタを生成するため、セレクタの再定義のリスクを排除できます。
このように、EffCSSは従来のCSS作成の枠を超え、CSS-in-TSのような役割を実現します。