CSS設計を数年試行錯誤して辿り着いた一つの答え(2024年版)
目次
はじめに
こんにちは、デジタルエンジニアリング部の島田です。
今回はフロントエンドエンジニアにとって基礎的でありながらもはっきりとした正解のない「CSS設計」について、記事を書きました。 私が長らく試行錯誤し落ち着いた、主流の設計手法の(主観的ですが)良いとこどりをしたものをご紹介したいと思います。
CSS設計を考える理由
CSSに触れたことがある人であれば分かるかと思いますが、CSSはLP1ページであろうと数百行の記述になりがちです。 また、サイトの規模が大きくなればなるほど、CSSを1ファイルで保守をしていくのは難しくなっていきます。
そのために考えられたのが「CSS設計」というものであり、内容としては主にクラスの命名規則やファイル構成をルール化したものになります。
どんな基準で作られているか
皆さんは「よいCSS」とはどんなものだと思いますか? 「よいCSS」には有名な4つの定義があります。
- 予測しやすい
- 再利用しやすい
- 保守しやすい
- 拡張しやすい
CSS設計手法を定めることにより、前述した定義を守りやすくなり、複数人や大規模サイトでの構築に耐えうるものとなるのです。
使用している設計手法
CSS設計のなにかを使おう!と意気込んでも「結局どれがいいの…?」と悩むことはなかったでしょうか?
私はある程度ゆとりを持って作業できた時期があったので、一通り試してみました。
まずはCSS設計で主流なものをいくつか挙げていきます。
・OOCSS
・FLOCSS
・BEM
・SMACSS
もちろんこの他にも様々なものがありますが、本記事で取り扱ったおすすめの設計手法は以下になります。
・FLOCSS
・BEM
結論から申し上げますと、
構成:FLOCSS(に近しい)
命名規則(思想):BEM(に近しい)
といった形に落ち着きました。
次からどういったアレンジをしたのかを説明していきます。
構成
最初に構成についてです。
本記事ではSCSSを使用する前提で進めていきます。
FLOCSSは通常以下のような構成をとっています。
└─ sass
├─ foundation // リセットCSSや基本的なスタイル
│ ├─ _base.scss
│ └─ _reset.scss
│
├─ global // 変数、mixin、関数ファイル
│ ├─ mixin // mixin(メディアクエリ設定など)
│ │ └─ _breakpoint.scss
│ │
│ ├─ setting // 変数$(カラー設定など)
│ │ └─ _color.scss
│ │
│ └─ _forwards.scss //@forwordとして関数をまとめる
│
├─ layout // ヘッダー・メインのコンテンツエリア・サイドバー・フッターのスタイル
│ ├─ _l-footer.scss //フッターのスタイル
│ ├─ _l-header.scss //ヘッダーのスタイル
│ ├─ _l-main.scss //mainタグ・sectionタグのスタイル
│ └─ _l-sidebar.scss //サイドバーのスタイル
│
├─ object // 繰り返し使用されるビジュアルパターン
│ ├─ component //単一パーツ(ボタン・見出しなど)
│ │ ├─ _c-button //ボタン類
│ │ ├─ _c-headline //見出し類
│ │ └─ _c-info-category //お知らせ一覧用のカテゴリーアイコン類
│ │
│ └─ project // 複合パーツ(ナビゲーション・記事一覧・画像ギャラリー・ユーザープロフィールなど)
│ ├─ _p-nav.scss //pc用ナビゲーションのスタイル
│ └─ _p-sp-nav.scss //スマホ用ナビゲーションのスタイル
│
└─ pages // ページ単位のスタイル(投稿ページ・下層固定ページなど)
├─ 01_home
│ └─ _front-page.scss //トップページ専用のスタイル
├─ 01_page
│ └─ _page.scss //下層固定ページ共通のスタイル
├─ 01_single
│ └─ _single.scss //投稿ページ共通のスタイル
└─ その他(カスタム投稿など必要に応じて増設していく)
参考:FLOCSSのSassファイル構成と書き方のコツ|CSS設計の効率化
こちらを以下のように変更しました。
└─ sass
├─style.scss // 全てのCSSをインポートするファイル
│
├─ foundation // 基本的なスタイルや変数/mixin
│ ├─ _base.scss
│ ├─ _var.scss
│ ├─ _mixin.scss
│ └─ _reset.scss
│
├─ layout
│ ├─ _l-footer.scss //フッターのスタイル
│ ├─ _l-header.scss //ヘッダーのスタイル
│ └─ _l-sidebar.scss //サイドバーのスタイル
│
├─ component // 複数箇所で使用されるパーツ
│ ├─ _c-button.scss
| └─ _c-heading.scss
│
├─ utility // pc/spでの表示の切り替えやmargin,paddingなどをクラスで付与できるもの
│ ├─ _u-device.scss
| └─ _u-margin.scss
│
└─ pages // ページ単位
├─ about
│ └─ _p-company.scss
│ └─ _p-access.scss
└─ ...その他ページや階層単位でファイル・ディレクトリを切っていく
基本的にはFLOCSSの構成に準拠していますが、以下が大きな相違点になります。
- 「object」のフォルダを廃止
- 「object/component」、「object/utility」フォルダの階層を上げる
- 「object/project」のフォルダを廃止
理由としては、
- 「object」のフォルダを廃止
→階層を深くするよりもsass直下のフォルダから分岐していく方がわかりやすいと感じたため
- 「object/component」、「object/utility」フォルダの階層を上げる
→「object」のフォルダ廃止に伴う移動
- 「object/project」のフォルダを廃止
→個人的にはcomponents/pagesでの管理の方がわかりやすいと感じたため
といった感じです。
FLOCSSの良いところは、接頭字の.l-
などがついていることにより、どこのフォルダ内に書かれているCSSなのかが明確に分かることです。
また、複数人で作業する場合、メイン作業者1人とサブ作業者数人という構成で作業することが多々あるかと思いますが、その際、サブ作業者はpages
配下のフォルダ内に新しくファイルを作成して作業し、メイン作業者はその他のファイルを触るというふうに分担をすれば、マージ時のコンフリクトが起こりづらく、コミュニケーションコストが下がることが嬉しいポイントです。
長らくFLOCSSの構成で運用した末にデメリットをほとんど感じなかったので、FLOCSS信者になっています。
命名規則
基本的なルール
次に命名規則についてです。
基準になる考えとしてはBEMを採用しています。
BEMは以下のような命名規則になります。
.Block__Element–-Modifier
それぞれの単語の意味をざっくりと記載します。
Block・・・ブロック
→大枠となる独立した要素
Elment・・・要素
→Block中の要素
Modifier・・・装飾
→BlockやElementのスタイル
この3つの要素を_(アンダーバー)
、-(ハイフン)
を2つずつ繋げていく形になります。
例として挙げると以下のような使い方になります。
.header__logo
.news__link--red
最初はBEMの規則に則り全く同様のルールで使っていたのですが、何点か気になるポイントが出てきました。
- クラス名がとんでもなく長くなることが多々あり、HTMLファイルCSSファイルどちらでも記述が煩雑に見えてしまう
- 名付ける際に、この要素が「Element」なのか「Modifier」なのか迷うことがある
- 「Modifier」の受け取り方が人それぞれで命名基準が作業者によって揺らいでしまう
- 「Modifier」をつけると「Block」、「Element」が共通のクラスに対して共通のCSSをつけたいというよくあるシチュエーションで記述に工夫が必要になる
例)HTML:.form__button--regist
.form__button--login
同様のCSSをつけたい場合、以下のような記述になるが複数クラスを付与する場合このクラスを一番最初に持ってこなければ反映されない。
CSS:[class^="form__button"] {}
部分一致にしてもいいけど予期せぬ挙動になる可能性がある…
そのため、この問題点を解決すべくまとまった結果が以下のようになりました。
.Block_Element
Block・・・ブロック
→大枠となる独立した要素
Element・・・要素
→Blockを作ったらBlockの中身はElementとする
もはや「BEM」ではなく「BE」になってしまいました。
作業において、迷う時間というのは大敵です。
工夫によって短縮ができるものなので、どうしてもこれをなくしたいなと考えました。
問題点として「Modifier」にまつわることが多かったので、いっそのこと「Modifier」の概念を消してしまえ!と大胆に舵を切ったところ、結果的にあまり不自由をしませんでした。
また、単語同士を繋げる記号は_(アンダーバー)
1つのみとしました。
単語数が少なくなったことにより記号を2つ繋げることでの可読性というメリットが下がったことと、クラスをカチカチとクリックしたときにアンダーバーだとクラス名ごとまるっと選択できるという点で選ばれました。
クラスをコピペしたい時にこちらの方が便利だと感じたので、サンプルを置いておくので比べてみてください↓
.hoge-huge
:クリックすると単語ごとに区切られて選択される.hoge_huga
:クリックすると全ての単語が選択される
状態管理などの記述
基本的なものは上述の通りですが、例えばタブやアコーディオンなど要素によっては活性化や表示/非表示を切り替えた時用にクラスを付与する必要があります。
その場合のみ、他のクラスとの差別化のため-(ハイフン)
を使用しています。
また、.is
を最初につけることで状態管理用のものと見分けがつきやすくなるようにしています。
サンプルコードは以下のようになります。
<ul class="tab_list">
<li class="tab_item is-current">タブ1</li>
<li class="tab_item">タブ2</li>
<li class="tab_item">タブ3</li>
<li class="tab_item">タブ4</li>
</ul>
まとめ
いかがでしたでしょうか。
今回ご紹介した設計について簡単にまとめたものを置いておきます。
構成(FLOCSSを基にアレンジ)
└─ sass
├─ foundation
├─ layout
├─ component
├─ utility
└─ pages
命名規則(BEMを基にアレンジ)
.block_element
もちろんこの命名規則が正解!といったものはないので、どなたかの参考になっていれば嬉しいです。
良いフロントエンドライフを!
アジアクエスト株式会社では一緒に働いていただける方を募集しています。
興味のある方は以下のURLを御覧ください。