コンテンツへスキップ

8層を理解する

各層の「なぜ」を知ることで、「どこに書くか」の判断基準が身につきます。
このサイト自身の実装コードを例に解説します。

※ コード例では層の所属を明示するため @layer ラッパーで表記していますが、 このサイトの実装では style.css@import layer() で層を一元管理しています。

Tokens

プリミティブトークン

意味を持たない「素材」を定義する層。色コード、フォント名、数値スケールなど。 「この青色の oklch 値はいくつか?」に答える層です。

tokens/color.css — このサイトの実装
@layer tokens {
  :root {
    --slate-600: oklch(44% 0.06 240deg);
    --vermilion-500: oklch(55% 0.24 25deg);
    --neutral-900: oklch(17% 0.008 240deg);
    --white: oklch(100% 0 0deg);
  }
}

判断基準: 値に意味を持たせない。--slate-600 は「スレートの 600 番」であり、「メインカラー」ではない。

Theme

Tokens のセマンティックマッピング

Tokens に意味のある名前を与える層。「プライマリカラーとしてどの色を使うか?」に答えます。 ダークモードは、この層だけを切り替えることで実現します。

theme/color.css — light-dark() でダークモード統合
@layer theme {
  :root {
    color-scheme: light dark;

    --color-main: light-dark(var(--slate-600), var(--slate-400));
    --color-accent: light-dark(var(--vermilion-500), var(--vermilion-400));
    --color-bg: light-dark(var(--neutral-50), var(--neutral-900));
    --color-text: light-dark(var(--neutral-900), var(--neutral-50));
  }
}
Foundation

ブラウザ環境の初期化と基本スタイル

リセット CSS と要素セレクタのデフォルトスタイル。クラスを使わず、HTML 要素そのものに適用する。 :where() で詳細度をゼロに保ち、上位の層で確実に上書きできるようにします。

foundation/base.css — このサイトの実装
@layer foundation {
  :where(body) {
    font-family: var(--font-family-ja);
    color: var(--color-text);
    background-color: var(--color-bg);
  }
  :where(a) {
    color: var(--color-main);
    text-decoration: none;
  }
}

判断基準: 「ブラウザ環境の初期化・要素の基本スタイルか?」 → Yes なら Foundation。

Layout

位置と空間の配置

「配置と空間」だけを担当する層。中身の見た目(色、フォントサイズ等)には一切関与しません。 このページのセクション間の余白は l-section、中央寄せは l-inner が担当しています。

layout/l-section.css — このサイトの実装
@layer layout {
  .l-section {
    container-type: inline-size;
    container-name: section;
    padding-block: clamp(/* fluid spacing */);

    &.-flush { padding-block-start: 0; }
  }
}

判断基準(Layout Test): 「色・文字・装飾に触れているか?」 → 触れているなら Layout ではない。

Component

再利用パーツ

別のサイトにそのまま持っていけるか?(Portability Test) これが Component の判断基準です。 ボタン、カード、バッジ、テーブル——このページで使われているパーツの多くが Component です。

Modifier パターン — c-button-cta の例
@layer component {
  .c-button-cta {
    background-color: var(--color-main);

    &.-large { font-size: 1.125rem; }
    &.-accent { background-color: var(--color-accent); }
  }
}

Modifier.-large のようにハイフン始まりの短縮記法。 BEM の --modifier より簡潔で、HTML の可読性が向上します。

Project

サイト固有のパーツと文脈

サイト固有の文脈を持つパーツか? これが Project の判断基準です。 ヘッダー、フッター、ヒーローセクション——これらは mFLOCSS サイト固有のデザインなので Project です。

Component は「パーツ単体」で完結する。Project は「Component を組み合わせて構成される」。

例えば、このサイトのヒーローセクション(p-hero)は、 中に c-button-cta(Component)を含んでいます。 Project は Component を組み合わせて、サイト固有の文脈を作ります。

State クラス: .is-current のような動的な状態変化は State クラスで管理。 Modifier(静的なバリエーション)とは区別します。

Animation

動きの分離管理

アニメーションを他の層から分離し、prefers-reduced-motionscripting の 2 条件(2 ガード原則)への対応を一元管理する層。 アクセシビリティを「仕組み」で担保します。

animation/a-fade-in-slide-up.css
@layer animation {
  @media (prefers-reduced-motion: no-preference)
     and (scripting: enabled) {
    .a-fade-in-slide-up {
      opacity: 0;
      translate: 0 20px;

      &.is-active {
        opacity: 1;
        translate: 0 0;
        animation: fade-in-slide-up 0.6s var(--ease-out-cubic);
      }
    }
    @keyframes fade-in-slide-up {
      from { opacity: 0; translate: 0 20px; }
    }
  }
}

判断基準: アニメーションは Animation 層に集約。@media ラッパーで prefers-reduced-motionscripting を一元管理する。

Utility

単一目的のスタイル上書き

最後の手段。 他の層で解決できない局所的な微調整のみに使います。 !important で最高優先度を保証し、どの層のスタイルも確実に上書きします。

utility/u-hidden.css
@layer utility {
  .u-hidden-pc {
    @media (width >= 768px) {
      display: none !important;
    }
  }
  .u-visually-hidden {
    position: absolute !important;
    inline-size: 1px !important;
    block-size: 1px !important;
    clip-path: inset(50%) !important;
    /* スクリーンリーダーには読み上げられる */
  }
}

判断基準: 「Utility でないと解決できないか?」 → Component や Project で対応できるなら、そちらに書く。

判断基準を身につけたら

このサイトのソースコードが、そのまま mFLOCSS の実装例です。
src/css/ の各ディレクトリを覗いて、設計判断を確認してみてください。