Skip to content

BEM型

StyleSheet maker関数は、特殊な型を使用して生成されるスタイルを記述できます。そのため、これらの関数を使用すると、TypeScriptは利用可能なCSSセレクタを提示します。この機能は、BEMの手法とTypeScriptのジェネリクスを組み合わせ、スタイルの実装を外部インターフェースの背後に隠蔽します。

特定の手法に厳密に依存しない型の使用を推奨します。詳細については、CSS-in-TSのセクションを参照してください。

スタイルの説明

EffCSS を用いてスタイルを開発する最初のステップは、提供する機能を、BEMメソッドの3つのレベルでスタイルを記述する型として宣言することです。

  • ブロック(第1レベル)、
  • 要素(第2レベル)、
  • 修飾子(第3レベル)。

すべてのレベルにおいて、lowerCamelCase スタイルで記述された、意味のある名前を使用することをお勧めします。

WARNING

名前にはドットとアンダースコアを使用しないでください。これらの文字はEffCSSのセレクタと属性を出力するために使用されます。

INFO

3つのレベルすべてを使用する必要はありません。BEMを使用してスタイルを記述したくない場合は、個々のブロックのレベルでセレクターを記述するだけで構いません。

ts
export type TCustomMaker = {
    /**
     * Default block
     */
    '': {
        /**
         * Logo element
         */
        logo: {
            /**
             * Spin animation
             */
            spin: '';
            /**
             * Logo scale
             */
            scale: 1 | 2;
        };
        /**
         * Body element
         */
        body: {
            /**
             * Padding size
             */
            p: 's' | 'm' | 'l';
        };
        /**
         * Footer element
         */
        footer: {
            /**
             * Is footer hidden
             */
            hidden: '';
        };
    };
    /**
     * Panel block
     */
    panel: {
        /**
         * Default block
         */
        '': {
            /**
             * Is panel modal
             */
            modal: '';
            /**
             * Max panel width
             */
            max: 'vw' | 'parent';
        };
        /**
         * Close button block
         */
        closeBtn: {};
    }
};

ブロックには要素を含める必要はありません。要素には修飾子を含める必要はありません。

ブロック修飾子は、キー「""」を持つ要素内のレベル3でも記述されていることに注意してください。キー「""」を持つブロックは、デフォルトまたはプライマリブロックとみなされます。スタイルによっては、特定のブロックや要素に紐づいていないユーティリティ(Tailwindなど)を記述している場合もあります。その場合は、以下の説明が役立ちます。

ts
export type TCustomMaker = {
    '': {
        '': {
            /**
             * Width 
             */
            w: 's' | 'm' | 'l';
            /**
             * Height 
             */
            h: 's' | 'm' | 'l';
        }
    };
};

スタイルの実装

EffCSS を用いたスタイル開発の2番目のステップは、StyleSheet maker 関数内に、説明した機能を実装することです。EffCSS では、bem ユーティリティを使用して BEM セレクタを生成します。このユーティリティは汎用的なため、実装された CSS セレクタの有効性もチェックします。

各セレクタは、ブロック名、要素名、修飾子名、および修飾子値(ブール値でない場合)をドットで結んで構成されます。

ts
import { TStyleSheetMaker } from 'effcss';

export type TCustomMaker = {...};

const maker: TStyleSheetMaker = ({
  bem,
}) => {
  return {
    // the default block selector
    [bem<TCustomMaker>('')]: {...},
    // selector for an element inside the default block
    [bem<TCustomMaker>('.logo')]: {...},
    // element boolean modifier selector
    [bem<TCustomMaker>('.logo.spin')]: {}
    // selector for a block modifier with a specific value
    [bem<TCustomMaker>('panel..max.vw')]: {}
  }
};

export default maker;

スタイルの使用方法

既製のEffCSSスタイルは、対応するStyleSheet maker関数をStyle providerオブジェクトのuseメソッドに渡すことで使用できます。使用方法はbemユーティリティと同様です。入力された引数は、TCustomMaker型に準拠しているかどうかもチェックされます。

ts
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';

const getStyle = (use: IStyleProvider['use']) => {
    // EffCSS v3 returns a resolver function,
    // and EffCSS v4 returns an array of resolvers
    // you can also const [css] = use(customStyle);
    return {
        block: css<TCustomMaker>(''),
        logo: css<TCustomMaker>('.logo'),
        spinLogo: css<TCustomMaker>('.logo.spin'),
        footer: css<TCustomMaker>('.footer'),
        body: css<TCustomMaker>('.body.p.m'),
    };
};

オブジェクトを渡すことで、複数のセレクタを一度に生成することもできます。

ts
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';

const getStyle = (use: IStyleProvider['use']) => {
    // EffCSS v3 returns a resolver function,
    // and EffCSS v4 returns an array of resolvers
    const [css] = use(customStyle);
    return css<TCustomMaker>({
        '': {
            logo: {
                spin: '',
                scale: 2
            };
        }
    });
};

または、文字列の配列を渡すこともできます。

ts
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';

const getStyle = (use: IStyleProvider['use']) => {
    // EffCSS v3 returns a resolver function,
    // and EffCSS v4 returns an array of resolvers
    const [css] = use(customStyle);
    return css<TCustomMaker>(['.logo.spin', '.logo.scale.2']);
};

あるいは、まず MonoResolver オブジェクトを取得し、必要に応じてそれを調整することもできます。

ts
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';

const getStyle = (use: IStyleProvider['use']) => {
    // EffCSS v3 returns a resolver function,
    // and EffCSS v4 returns an array of resolvers
    const [css] = use(customStyle);
    const block = css<TCustomMaker>();
    const logo = block.e('logo');
    const logoSpin = logo.m({
        spin: ''
    });
    return {
        block: block.$,
        logo: logo.$,
        spinLogo: logoSpin.$,
        footer: block.e('footer').$,
        body: block.e('body').m({
            p: 'm'
        }).$,
  };
};

お好みの方法でご利用ください。

属性生成モード

Style provider コンポーネントは、以下の2つの属性を使用してBEMセレクタの生成を制御できます。

  • modeadata-*属性を使用)とcclass属性を使用)の2つの値を指定できます。
  • min:BEMセレクタを最小化するためのブール値属性です。

CSSクラス生成はより予測可能であり、データ属性生成は異なるスタイルシートを視覚的に区別するのに役立ちます。お好みの方法でご利用ください。

最小化によってセレクタに固有のプレフィックスが保持されるため、異なるテーブルのスタイルは分離されたままになり、セレクタの長さは大幅に短縮されます。

メリット

このアプローチにより、契約と実装を分離できます。開発段階では、どのCSSセレクタを提供すべきかが最初から分かっているため、サードパーティの開発者はTCustomMaker型をインポートするだけで、StyleSheet maker関数を参照することなく必要なスタイルを取得できます。JavaScriptファイルは通常アセンブリ時にミニファイされるため、このアプローチは大幅な時間短縮につながります。

さらに、EffCSSは各スタイルシートごとに独自のBEMセレクタを生成するため、セレクタを再定義するリスクを排除できます。

このように、EffCSSは従来のCSS作成の枠を超え、CSS-in-TSのような役割を実現します。

Apache License 2.0に基づいて公開されています。