8層を理解する
各層の「なぜ」を知ることで、「どこに書くか」の判断基準が身につきます。
このサイト自身の実装コードを例に解説します。
※ コード例では層の所属を明示するため @layer ラッパーで表記していますが、
このサイトの実装では style.css の @import layer() で層を一元管理しています。
プリミティブトークン
意味を持たない「素材」を定義する層。色コード、フォント名、数値スケールなど。 「この青色の oklch 値はいくつか?」に答える層です。
@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 番」であり、「メインカラー」ではない。
Tokens のセマンティックマッピング
Tokens に意味のある名前を与える層。「プライマリカラーとしてどの色を使うか?」に答えます。 ダークモードは、この層だけを切り替えることで実現します。
@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));
}
}
ブラウザ環境の初期化と基本スタイル
リセット CSS と要素セレクタのデフォルトスタイル。クラスを使わず、HTML 要素そのものに適用する。
:where() で詳細度をゼロに保ち、上位の層で確実に上書きできるようにします。
@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。
位置と空間の配置
「配置と空間」だけを担当する層。中身の見た目(色、フォントサイズ等)には一切関与しません。
このページのセクション間の余白は l-section、中央寄せは l-inner が担当しています。
@layer layout {
.l-section {
container-type: inline-size;
container-name: section;
padding-block: clamp(/* fluid spacing */);
&.-flush { padding-block-start: 0; }
}
}
判断基準(Layout Test): 「色・文字・装飾に触れているか?」 → 触れているなら Layout ではない。
再利用パーツ
別のサイトにそのまま持っていけるか?(Portability Test) これが Component の判断基準です。 ボタン、カード、バッジ、テーブル——このページで使われているパーツの多くが Component です。
@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 の判断基準です。 ヘッダー、フッター、ヒーローセクション——これらは mFLOCSS サイト固有のデザインなので Project です。
Component は「パーツ単体」で完結する。Project は「Component を組み合わせて構成される」。
例えば、このサイトのヒーローセクション(p-hero)は、
中に c-button-cta(Component)を含んでいます。
Project は Component を組み合わせて、サイト固有の文脈を作ります。
State クラス: .is-current のような動的な状態変化は State クラスで管理。
Modifier(静的なバリエーション)とは区別します。
動きの分離管理
アニメーションを他の層から分離し、prefers-reduced-motion と scripting の 2 条件(2 ガード原則)への対応を一元管理する層。
アクセシビリティを「仕組み」で担保します。
@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-motion と scripting を一元管理する。
単一目的のスタイル上書き
最後の手段。
他の層で解決できない局所的な微調整のみに使います。
!important で最高優先度を保証し、どの層のスタイルも確実に上書きします。
@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/ の各ディレクトリを覗いて、設計判断を確認してみてください。