Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
344
Help us understand the problem. What is going on with this article?
@super-mana-chan

[CSS設計] 私のためのFLOCSSまとめ

2020/09/24 更新
flocssを使い始めて1年経過
使い始めに書いたこの記事を1年使ってみた経験から編集し直しました


下記の記事を参考にFLOCSS設計のコーディングルールをまとめた

FLOCSS生みの親による基本ルール
hiloki/flocss: CSS organization methodology.

ComponentとProjectの違い
FLOCSSを使ったCSS設計での悩みどころと解決案 - Qiita

脱・CSS無法地帯。FLOCSSで指針のある設計を。 - Qiita
FLOCSSを使ってCSSファイルを20,000行から9,000行にした話 - Qiita

命名規則
CSSの設計 – FLOCSSをベースにしたファイルの構成と命名規則を考える | Tips Note by TAM

BEM
BEM記法におけるElement/Modifierの付け方メモ - Qiita

FLOCSSとは

「Foundation Layout Object CSS」
OOCSSやBEM、SMACSSのいいとこ取りをしたCSS設計思想。

構造

Foundation サイト全体のデフォルトスタイルを管理。
├ reset.scss
├ base.scss
├ variable.scss サイト全体で使える変数
├ mixin サイト全体で使えるmixnを管理
Layout 各ページを構成するサイト全体で共通したエリアを管理。
├ l-header.scss
├ l-main.scss
├ l-footer.scss
Object サイト全体で再利用できるパターンを持つモジュールを管理
Component 小さな単位のモジュールを管理(ボタンなど)
 ├ c-button.scss
 ├ c-grid.scss
 ├ …
Project いくつかの↑Componentと、他の要素によって構成される大きな単位のモジュールを管理
 ├ p-card.scss
 ├ p-profile.scss
 ├ ...
Utility ComponentとProjectのモディファイア(パターン)で解決することができないスタイル、また、調整のための便利クラスなどを管理。
 ├ u-utility.scss
 ├ u-color.scss
 ├ u-margin.scss
 ├ u-padding.scss
Theme テーマによる色の切り替えなど、ページ単位の色違いとか
 ├ t-blue.scss
 ├ ...

Foundation

サイト全体のデフォルトスタイルを管理。

reset.scss

ブラウザのデフォルトのスタイルをリセットするcssを定義
(よく使う:HTML5 Reset Stylesheet
HTML5 Doctor Reset CSSは古くなってきたため、destyle.cssを採用

▼説明
2020年版!おすすめのリセットCSSまとめ#destylecss | Web Design Trends

base.scss

サイトを構成する上で、デザインの基本の下地、土台となるスタイルを定義
※基本的にタグ自体にスタイルを定義すること。
※クラスなしの状態でも最低限の表示になることを心がける

Layout

各ページを構成する、ヘッダー、メインコンテンツエリア、サイドバー、フッターなどのスタイルをエリアごとに管理
※ページ全体からみたレイアウトに対するスタイルを定義する
※外枠のみ定義。子要素はなるべく入れない
※ヘッダーやフッターの中身はp-で定義する

l-header,p-headerの例
//ページ全体からみたレイアウトに対するスタイル
.l-header {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  width: 100%;
}
//ヘッダーというパーツのスタイル
.p-header {
  display: flex;
  &__logo{
    width:100px;
    height:50px;
    ...
  }
  ...
}

l-header.scss

ヘッダーのスタイルを定義

(l-nav.scss)

navは画面構造によってp-navとしてl-headerのなかに入ることもあるが、l-という大枠のほうがやりやすければLayoutでオーケー。

l-main.scss

メインのコンテンツエリアの共通スタイルを定義
※ヘッダーのfixed分の相殺や余白など
※ここでは共通の上下左右の余白などのみの定義

l-container.scss

サイトのメインエリア内のコンテンツ幅などの指定

l-footer.scss

フッターエリアのスタイルを定義

Object

サイト全体における、繰り返されるビジュアルパターンをすべてObjectと定義。

- Component

再利用できるパターンとして、小さな単位のモジュールを定義。
※marginなど余白は定義しない。あくまでパーツとして扱う

c-button.scss
c-grid.scss
c-input.scss


flexboxのレイアウトシステムもコンポーネント化する

flexboxのレイアウトシステム(Bootstrap4のrow,colなど)は、Layoutとして管理しそうになるがComponentとして管理する。

理由は、各ページに必ずある共通エリアとは限らないから
containerは絶対ページにいるやつだけど、rowは絶対いるとは限らない。規則性なく出てくるやつだからLayoutにするのはなんか違う気もしてきたので。

c-gridの例
<main class="l-main">
  <div class="c-grid">
    <div class="c-grid__col-6"></div>
    <div class="c-grid__col-6"></div>
  </div>
</main>

- Project

いくつかのComponentと、それに該当しない要素によって構成されるものを管理。

つまり、

  • 小さい単位のComponentを集めて、一つのObjectとして扱いたい時
  • Componentとするには大きすぎるObjectとなる時

にProjectとして定義する。

アイコン付きボタンはp-buttonc-buttonを並列にする

p-buttonの例
<a class="p-button p-button--icon c-button" href="/">
  <img src="icon-arrow.jpg" class="c-icon--arrow">
  <span>お問い合わせ</span>
</a>

ComponentとProjectの違い

人間で言えば、裸んぼの人間が最小単位のモジュールcomponentで、他にネクタイや靴下、スーツといったcomponentがあり、組み合わせてビジネスマンprojectになると考えられます
(抜粋:FLOCSSを使ったCSS設計での悩みどころと解決案 - Qiita

ここを読んでかなりしっくりきた。

  • 小さい単位をComponent
  • Componentの集まりをProject

やったー!


- Utility

u-margin.scss
u-color.scss
u-fontsize.scss
u-clearfix.scss
...

Component、ProjectのObjectを無駄に増やしてしまうことを防せぐ。
Object自体が持つべきではないmarginの代わりに.u-mb10 { margin-bottom: 10px; }のような隣接するモジュールとの間隔をつくるといった役割。

すべての余白marginをUtilityクラスでつけることはしない。
あくまで補助としての役割であること。

Projectとして定義するには要素が少なすぎる場合component単体で使うときに使用

命名規則

プレフィックス

layoutならl-Componentならc-のように、属してるフォルダ名の{頭文字}+- でプレフィックスを頭につけ、ファイル名だけでもで判断しやすくする(Foundationはリセットや下地が目的なので除く)

l-header.scss
l-footer.scss
c-button.scss
p-card.scss

ファイル名=クラス名

l-header.scssにはl-headerというクラス名を定義

ファイル名、クラス名なるべくは省略しない

誰が見てもわかるようにファイル名、クラス名なるべくは省略しない
txtbtnもNG。自分で言葉を作らないこと。
ただし、Utilityはクラス名が長くなりがちなので省略可とし、ファイル名は省略しないことで誰が見てもわかるようにする。

MindBEMdingの規則

BEMシステムのシンタックスである、Block、Element、Modifierに分類して構成される規則。
(参考:BEMとMindBEMdingの命名規則の違い - コード日進月歩

Modifier

Modifierは原則2つまでとする
c-button--blue,c-button--smallなど)

{Block}--{Modifier}
<!--ボタン-->
<button class="c-button"></button>
<!--ボタンの色違い+サイズ違いモディファイア-->
<button class="c-button c-button--blue c-button--small"></button>
{Block}__{Element}
<!--ボックス-->
<div class="c-box">
  <!--ボックスコンポーネントの子要素-->
  <div class="c-box__inner"></div>
</div>

ElementへのModifierは??となったので調べたらとってもわかりやすかった記事発見。
BEM記法におけるElement/Modifierの付け方メモ - Qiita
Block + Modifier + Modifierにならなければ良いっぽい。

ElementへのModifierは良いとしていたが、
どんなときにElementへのModifierを良いとするかなど細かくルールを決めないと破綻しやすく、第三者が見たときに分かりづらかった(特にcomponent

そのため、p-c-も、{Block}--{Modifier}__{Element}とすることを推奨する。

JavaScriptで操作され、状態を変化させるためのクラス

プレフィックスにis-をつけ、定義する
この場合、他のObjectへの変化にスタイルを当ててしまうことを防ぐために、
is-click自体にスタイルは定義せず、必ず、.c-button.is-clickにスタイルを定義する。

JavaScript用のクラス
<!--ボタン-->
<button class="c-button is-click"></button>

カスケーディング

カスケーディングとは,ある要素のあるプロパティに対する宣言が複数あるとき,宣言の“強さ”の関係を定めて,うち 1 つの宣言だけが有効になるようにするしくみである(抜粋:Let's begin CSS -- 2.5

モジュール間のカスケーディング、他のモジュールを親とするセレクタを用いたカスケーディングは禁止

つまり下記のようにProjectを親に持つ別のProjectにスタイルを定義するのはだめ。

だめな例

// Component
.c-button {
  ...
}
.c-dialog>.c-button { 
  /*c-dialogを親に持つc-buttonのみスタイルを指定してしまってる!ダメ!*/
  ...
}

// Project
.p-comments {
  ...
}
.p-articles>.p-comments { 
  /*p-articlesを親に持つp-commentsのみスタイルを指定してしまってる!そんな書き方ダメ!*/
  ...
}

理由として、

特定のモジュールに依存することなく、モジュールとして独立して再利用できるべきであり、混在させることによって他の開発者が予想しない挙動になるべきではないためです。
(抜粋:hiloki/flocss: CSS organization methodology.

つまり、

  • 汎用的であるべきパーツ(例:c-button)が他のComponent内でしか力を発揮できなくなるのはおかしい
  • 混在することで第三者に、どれがもとのc-buttonのスタイルなのかc-buttonなのにここの下では変わってしまうこのc-buttonを使いたいのにならない、といった混乱を招いてはいけない

ということ。

ただし、ProjectComponentのを変更することはOK

Componentの集まりをObjectとしてProjectで管理してる場合、定義してる場合の余白などの調整は、Projectを親として持つComponentを変更しても良いとするが必ずクラス名を変更すること。

だめな例
<div class="p-profile c-media">
  <img src="user.jpg" class="c-media__image">
  <div class="c-media__body">...</div>
</div>

こういったときに、c-media__imageの余白をどうしても変えたい!となったら

だめな例
// c-media.scss内
.c-media__image {
  float: left;
  margin-left: 10px;
}

//p-profile.scss内
.p-profile > .c-media__image { //←ここだめ!
  float: right;
  margin-left: 0; 
  margin-right: 10px;
}

のように変えるのは絶対にNG!
理由は、p-profile内にc-media__imageがあるだけで第三者的には混乱するし、p-profileというObjectが成り立たないし、c-media__imagep-profileのなんなのか、理解しづらいため

そのため必ずクラス名をp-profileElementととし、c-media__imageと並列にかくこと。

良い例
<div class="p-profile c-media">
  <img src="user.jpg" class="p-profile__avatar c-media__image">
  <div class="c-media__body">...</div>
</div>
良い例
// c-media.scss内
.c-media__image {
  float: left;
  margin-left: 10px;
}

//p-profile.scss内
.p-profile > .p-profile__avatar { //←良い
  float: right;
  margin-left: 0; 
  margin-right: 10px;
}

Componentのモディファイア(パターン)を増やすことで対応可能な場合はそこで対応すること。
※ただしモディファイア(パターン)が2つ以上ある場合とする。

SASSのextend

例えば、.c-buttonのModifierをつくるには、下記のように一つのタグへModifierのクラスもつける必要がある

<!--ボタン-->
<button class="c-button"></button>
<!--ボタンの色違いモディファイア-->
<button class="c-button c-button--blue"></button>

だが、SASSのextendでc-buttonを継承し、タグへの記載はc-button--blueクラスのみにすることが出来る。

.c-button {
  ...
}
.c-button--blue {
  @extend .c-button;
  background-color: blue;
}

これでc-buttonクラスの記載の必要はなくなる!
クラスが増えることを防げる。

注意点:rolling_eyes:

Modifierを2つつけるとなんかややこしい気持ちになる

.c-button {
  ...
}
.c-button--blue {
  @extend .c-button;
  background-color: blue;
}
.c-button--small {
  @extend .c-button;
  width: 200px;
}
<!--ボタン-->
<button class="c-button"></button>
<!--ボタンの色違いモディファイア-->
<button class="c-button--blue c-button--small"></button>

:rolling_eyes:

BlockModifierをつけて、{Block}--{Modifier}__{Element}としたとき、すべてのElement@extendしなくてはならなくてめんどくさい

.p-box {
  ...
  &__inner{
    ...
  }
}

.p-box--round {
  @extend .p-box;
  ...
  &__inner{
    ...
    @extend .p-box__inner;
  }
}

:rolling_eyes:
慣れてvscodeの変換とか使えば楽だけど、デメリットから、拡張性があまりない気がした。

extend機能は採用していないが、htmlがすっきりするし、一つのタグにクラスは3つまでとしてる私としては結構好きな機能だった。
親要素をextendしたら、子要素もついてきてくれたら少しはやりやすいんだけどなあ...:upside_down:

344
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
super-mana-chan
heightは「ヘイト」じゃなくて「ハイト」
sorich
SORICHはWebシステム開発を主軸に、デザイン・Web制作・アプリ開発・IoTまで、クライアントの幅広いニーズに対応する技術者集団です。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
344
Help us understand the problem. What is going on with this article?