CSS の迷いをなくす、
層アーキテクチャ
v1.0 では 8 つの層で設計判断を体系化します。
@layer tokens, theme, foundation, layout, component, project, animation, utility;
プリミティブトークン
意味を持たない「素材」を定義する層。色コード、フォント名、数値スケールなど。「この青色の 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);
}
}
判断基準: 値に意味を持たせない。--slate-600 は「スレートの 600 番」であり、「メインカラー」ではない。
セマンティックテーマ
Tokens に意味のある名前を与える層。「プライマリカラーとしてどの色を使うか?」に答えます。ダークモードは Theme だけで切り替わります。
@layer theme {
:root {
--color-main: var(--slate-600);
--color-accent: var(--vermilion-500);
--color-bg: var(--neutral-50);
--color-text: var(--neutral-900);
}
}
判断基準: Tokens の値に「役割」を持たせたいか? → Yes なら Theme。
ベーススタイル
リセット CSS と要素セレクタのデフォルトスタイル。クラスを使わず HTML 要素そのものに適用します。:where() で詳細度をゼロに保ちます。
@layer foundation {
:where(body) {
font-family: var(--font-family-ja);
color: var(--color-text);
background-color: var(--color-bg);
}
}
判断基準: クラスなしの HTML 要素に適用すべきスタイルか? → Yes なら Foundation。
ページの骨格
「配置と空間」だけを担当する層。中身の見た目(色、フォントサイズ等)には一切関与しません。
@layer layout {
.l-grid {
--_columns: 3;
--_gap: 1.5rem;
display: grid;
grid-template-columns: repeat(var(--_columns), 1fr);
gap: var(--_gap);
}
}
判断基準: 色やフォントに触れているか? → 触れているなら Layout ではない。
再利用パーツ
別のサイトにそのまま持っていけるか? これが Component の判断基準です。ボタン、カード、バッジ——このページで使われているパーツの多くが Component です。
@layer component {
.c-button-cta {
background-color: var(--color-main);
&.-large { font-size: 1.125rem; }
&.-accent { background-color: var(--color-accent); }
}
}
判断基準: 別のサイトにそのまま持っていけるか? → Yes なら Component。
サイト固有パーツ
このサイトのデザインに依存しているか? ヘッダー、フッター、ヒーロー——これらは mFLOCSS サイト固有のデザインなので Project です。Component を組み合わせて、サイト固有の文脈を作ります。
判断基準: このサイトのデザインに依存しているか? → Yes なら Project。
動きの管理
アニメーションを分離し、prefers-reduced-motion 対応を一元管理する層。アクセシビリティを「仕組み」で担保します。
@layer animation {
.a-fade-in-slide-up {
opacity: 0;
translate: 0 20px;
transition: opacity 0.6s, translate 0.6s;
&.is-active { opacity: 1; translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
.a-fade-in-slide-up { opacity: 1; translate: 0 0; }
}
}
判断基準: reduced-motion で無効化すべき動きか? → Yes なら Animation 層に集約。
局所的な調整
最後の手段。 他の層で解決できない局所的な微調整のみ。!important で最高優先度を保証します。
@layer utility {
.u-visually-hidden {
position: absolute !important;
inline-size: 1px !important;
block-size: 1px !important;
clip-path: inset(50%) !important;
}
}
判断基準: Utility でないと解決できないか? → Component や Project で対応できるなら、そちらに書く。
「どの層に書くか」判断フロー
迷ったら、この順番で考えてみてください。
クラスを付けて使うスタイル?
No → Foundation(HTML 要素のデフォルトスタイル)
Yes → 次の質問へ
ページの骨格(配置・余白)に関するもの?
Yes → Layout(色やフォントに触れていないことを確認)
No → 次の質問へ
別のサイトにそのまま持っていける?
Yes → Component
No → Project(このサイト固有のパーツ)
reduced-motion で無効化すべき動き?
Yes → Animation(アクセシビリティ対応を一元管理)
他の層で解決できない局所的な微調整?
Yes → Utility(最後の手段)
No → Component か Project を再検討
なぜ、この順番なのか
@layer では、後に宣言された層ほど優先度が高くなります。mFLOCSS の 8 層は「抽象度が高いもの → 具体的なもの」の順に並んでいます。
@layer tokens, /* 1. 素材(最も抽象的) */
theme, /* 2. 意味付け */
foundation, /* 3. デフォルト */
layout, /* 4. 配置 */
component, /* 5. 再利用パーツ */
project, /* 6. サイト固有パーツ */
animation, /* 7. 動きの制御 */
utility; /* 8. 最終調整(最も具体的) */
Tokens が最低優先度なのは、他のすべての層から参照される「素材」だから。Utility が最高優先度なのは、どの層のスタイルも確実に上書きする「最終調整」だから。この順序は設計思想そのものです。