【CSS設計】FLOCSSって何?読みやすいCSSの書き方を説明します

css Programming

こんにちは。あっきーです。フリーのwebプログラマーとしてホームページ制作やサービスを作っている、
最近、夜活人間から朝活人間へと恐るべき進化を遂げた者です。

今回は「CSS設計の一つFLOCSSって超使えるよ」というテーマで話していきます。

CSSを書いている方でこんな経験したことありません?

  • 文字色とか背景とか変えたいけどどこに書いたか分からなくなった
  • クラスの名付け方に迷った
  • ちょっとした装飾にいちいち固有のクラスをつけるのはだるい

CSSって自由に書けるし、初学者にとっても優しいプログラミング言語なので、こういう困難にぶつかることは日常茶飯事なんですね。

このような「ごちゃごちゃ」を解決する方法がこのFLOCSSというものです。
詳しく見ていきましょう。

FLOCSSではSASS(もしくはSCSS)を使っていきます。これらについても勉強しておいてください。
あと、SASSを使うにあたってwebpackという機能も使っていくのでこれらの知識は最低限もっておきましょう。

FLOCSSはCSS設計の一つ

FLOCSSというのはCSSの書き方のテンプレートのことです(読み方は「フロックス」)。

「CSSをきれいに書く方法を考えましょう」というのを「CSS設計」と呼ぶのですが、CSS設計は研究されていて、何パターンかあります。

そのうち最も良い(と個人的に思っている)のがFLOCSSです。

FLOCSSはCSSファイルを3つの種類に分ける

cssファイルを原則3つのカテゴリーにわけて設計していきます。そのカテゴリーというのが以下の通り

  • Foundation(初期設定):サイト全体の初期設定を書いたもの
  • Layout(共通部分の設定):ヘッダーとかフッターとか共通で使われるもの
  • Component(部品の設定):部分部分で使うもの

またComponentは3つに分かれます。

  • component(使いまわし要素):ボタンなどサイト内で使いまわせるもの
  • project(大きめの部分的に使う要素):componentを複数使って構成されるもの
  • utility(ちょっとした装飾):「文字を赤にする」など1つだけの機能をもつもの

具体例を挙げながら説明しますが、ポイントは「CSSを機能別に分割していきますよ」ということです。

さっそく手を動かしながら書き方を見ていきましょう。
・・・の前に準備です。

sassやwebpackの準備

まず、sassやwebpackを使えるようにインストールします。
package.jsonファイルを作り、以下をコピペしてください。


{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "dev": "webpack --mode development",
    "production": "webpack --mode production",
    "watch": "webpack --mode development --watch"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "autoprefixer": "^10.2.5",
    "css-loader": "^5.2.0",
    "import-glob-loader": "^1.1.0",
    "mini-css-extract-plugin": "^1.4.0",
    "node-sass": "^5.0.0",
    "node-sass-glob-importer": "^5.3.2",
    "postcss-loader": "^5.2.0",
    "sass-loader": "^11.0.1",
    "style-loader": "^2.0.0",
    "webpack": "^5.28.0",
    "webpack-cli": "^4.6.0"
  },
}

あとはnpm installをすれば必要なものがインストールされます。

また、webpack.config.jsを作成し以下を書いてください。


// output.pathに絶対パスを指定する必要があるため、pathモジュールを読み込んでおく
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const globImporter = require('node-sass-glob-importer');

module.exports = {
  // モードの設定、v4系以降はmodeを指定しないと、webpack実行時に警告が出る
  mode: 'production',
  entry: './src/index.js',
  output: {
      filename: 'main.js',
      path: path.resolve(__dirname, 'dist'),
  },
  module: {
      rules: [
            {
                // 対象となるファイルの拡張子(scss)
                test: /\.scss$/,
                // sassファイルの読み込みとコンパイル
                use: [
                    // cssファイルを書き出すオプションを有効にする
                    {
                        loader: MiniCssExtractPlugin.loader,
                    },
                    // cssをバンドルするための機能
                    {
                        loader: "css-loader",
                        options: {
                            // オプションでcss内のurl()メソッドを取り込まない
                            url: false,
                            // ソースマップの利用有無
                            sourceMap: true,
                            // Sass + PostCssの場合は2を指定
                            importLoaders: 2,
                        },
                    },
                    // PostCssのための設定
                    {
                        loader: "postcss-loader",
                        options: {
                            //postcss側でもソースマップを有効
                            sourceMap: true,
                            postcssOptions: {
                                // ベンダープレフィックスを自動付与する
                                plugins: ["autoprefixer"],
                            },
                        },
                    },
                    // sassをバンドルするための機能
                    {
                        loader: "sass-loader",
                        options: {
                            // ソースマップの利用有無
                            sourceMap: true,
                            // importer: globImporter(),
                        },
                    },
                    {
                        loader: 'import-glob-loader'
                    }
                ],
            },
        ],
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: "style.css",
        }),
    ],
    // source-map方式でないと、CSSの元ソースが追跡できないため
    devtool: "source-map",
};

次にsrcフォルダを作成しその中にindex.jsを作成します。ここに以下を記述。


import "./style.scss";

これで、style.scss(これから作る)の内容がcssファイルに書き換えられるようになります。

FLOCSS用のフォルダを作成

次は先ほど見たようにファイルを分割するようのフォルダを作成しましょう。

srcフォルダの中にsassフォルダを作成します。
その中に以下のような構成でフォルダを作成してください。


/sass
 |- foundation
 |- layout
 |- object
     |- component
     |- project
     |- utility

最後にsrcフォルダ直下にstyle.scssを作成し、以下のように編集します。


@import './sass/foundation/**';
@import './sass/layout/**';
@import './sass/object/**';

ここでは、sassフォルダにあるすべてのファイルを一度style.scssで統合しています。

その後index.jsによってcssファイルに書き換えられます。
(今回の設定の場合、dist/style.cssが作られます。)

これで、準備は整いました。

FLOCSSのfoundation、layout, objectの機能

では、FLOCSSの3つのカテゴリーについて実際に手を動かしながら説明していきます。

foundation:基本設定を作ってみる

foundationフォルダにはサイト全体の設定を行います。具体的には以下の通り。

  • pタグやh2タグなど、各セレクタの初期設定(_reset.scss
  • sassで使う変数の定義(_variables.scss
  • sassで使う関数(mixin)の定義(_mixin.scss

ちなみに、ファイルの名前の付け方は決まっていて

  • クラス名をそのままつける(.l-headerについて書くならファイル名はl-header.scss
  • アンダーバー(_)+クラス名(.l-headerについて書くならファイル名は_header.scss

詳しくは以降で。当サイトでは2つ目を採用しています。

セレクタの初期設定を作る

htmlタグには最初からある程度レイアウトがついているものがあります。
pタグ,hタグにはmargin-bottomがついていますし、ulタグにはpadding-leftがデフォルトで設定されています。

他にもhタグの文字サイズだったり、aタグの文字色だったりも初期設定がされています。

webサイトを作る時にこういう設定が邪魔なことが多いので自分用に初期設定をしましょう。
ここでは省略します。

cssの初期化としてsanitize.cssやnormalize.cssなどがネット上に公開されているのでこれらを使うのが一般的ですね。

変数を定義する(_variables.scss

sassでは変数を定義することができ、これによってコードの記述が楽になります。
以下3つを定義しておくと後々便利だと思います。

  • サイズ
  • フォント

例としていくつか設定してみましょう。


//color
$blue : #00bfff;
$light-blue : #87cefa;

//size
$spacer : 1rem;
$text-lg : 1.25rem;

関数を定義する(_mixin.scss

また、sassでは関数を定義することができます。よく使う組み合わせを関数でまとめておくと記述量が減らせて見やすくなります。例として以下を書いてみましょう。


//flexの設定
@mixin flex($justify: center, $align:center) {
    display: flex;
    justify-content: $justify;
    align-items: $align;
}

よく使う例としてflexです。
基本的にjustify-contentalign-itemsがセットになるので関数にまとめておくと楽です。

layout:サイトで共通する要素を設定する

layoutではサイト全体で使う要素の設定を行います。サイト全体で使うものと言えば以下のタグですね。

  • header
  • main
  • footer
  • nav

例として、ヘッダーに用に作ってみます。_header.scssを作成して以下を記述。


.l-header {
    width: 100%;
    height: 50px;
    padding: $spacer;
}

いくつか注意があります。

  • サイズなど全体の設定のみを行う
  • l-の形でクラスを定義する

まず、layout部分では横縦幅や余白の設定だけをします。
そして、クラス名は原則l-から始まるようにします(このlはlayoutの頭文字)。
フッターについてならl-footer、navタグについてならl-navといった具合です。

これは他のカテゴリーでも同じです。

  • component → c-
  • project→ p-
  • utility→ u-

また、先ほどファイル名について触れたんですが、このl-とかの接頭語をそのまま使うか、_に書き換えるかのどちからで名付けてください。

layoutについては要素の数が唯一なので、idを使うのもOKです。
また、layoutは基本的にファイル数も記述量も少ないので安心してね。

object:部分要素を設定する

ここが一番重要です。ここは3つに分かれています。

component:再利用できる部分

componentには複数の場所で使える汎用性ありの要素について設定します。

bootstrapの知識がある人はそれと見比べてもらえばOKです。
例えばbootstrapでボタンを使いたいとき以下のように書きますよね。


<button class="btn btn-primary">ボタン</button>

これです。これがcomponentです。

1つボタンの装飾を作っておけばどこでも使えるようになるわけです。

試しに作ってみましょう。_button.scssを作成して、以下のように記述しましょう。


.c-button {
    padding: $spacer;
    border: none;
    border-radius: 10px;
    margin: $spacer;
    background: $blue;
    outline: none;
    transition: 300ms;
    &:hover {
        background: $light-blue;
    }
}

componentなのでクラス名はc-で始まります。
また最初に作った変数も使ってあげるとなお良いですね。

また、htmlにコードを書きましょう。


<a href="" class="c-button">もっと見る</a>

これで表示するとリンクボタンが出来上がります。

もう一つ例を出しましょう。_box-contentを作成して以下を記述。


.c-box-content {
    margin: $spacer;
    width: 300px;
    height: 300px;
    box-shadow: 1px 3px 6px #acacac;
    transition: 300ms;
    &:hover {
        transform: translateY(-10px);
    }
    &__img {
        img {
            width: 100%;
        }
    }
    &__title {
        font-weight: bold;
        font-size: 18px;
    }
}

そして、htmlでコードを書きます。


<div class="c-box-content">
    <div class="c-box-content__img"><img src="dist/img/TSU1994064_TP_V4.jpg" alt=""></div>
    <h2 class="c-box-content__title">こんにちは。</h2>
    <p class="c-box-content__description">プログラミングって楽しいよね</p>
</div>

するとカーソルを載せたときにふわっと浮くような部品が出来上がります。

ファイルごとに機能を分けるので、複数のものを書かないでくださいね。ボタンならボタンだけの機能を書きます。
こんな感じで、使いまわしできそうなものはcomponentでまとめていきます。

project:特定の場所で使う大きめの部品

ブログとかを作る時ってサイドバーにプロフィールを載せたり、トップページに記事一覧などを載せたりしますよね。
「プロフィール」や「記事一覧」はコンポーネントにするには大きすぎるので、projectに入れてしまいます。

試しにやってみましょう。ここではランキングを作ってみます。

_ranking.scssを作成し以下を追加。


.p-ranking {
    background: #ececec;
    &__content {
        @include flex
    }
}

htmlでは以下のように記述。


<div class="p-ranking">
    <div class="p-ranking__content">
        <div class="c-box-content">
            <div class="c-box-content__img"><img src="dist/img/TSU1994064_TP_V4.jpg" alt=""></div>
            <h2 class="c-box-content__title">1位!!</h2>
            <p class="c-box-content__description">やった1位!</p>
        </div>
        <div class="c-box-content">
            <div class="c-box-content__img"><img src="dist/img/TSU1994064_TP_V4.jpg" alt=""></div>
            <h2 class="c-box-content__title">2位!!</h2>
            <p class="c-box-content__description">まあまあ2位!</p>
        </div>
        <div class="c-box-content">
            <div class="c-box-content__img"><img src="dist/img/TSU1994064_TP_V4.jpg" alt=""></div>
            <h2 class="c-box-content__title">3位!!</h2>
            <p class="c-box-content__description">ミスった3位!</p>
        </div>
    </div>
    <div class="d-flex justify-content-end">
        <a href="" class="c-button">もっと見る</a>
    </div>
</div>

(一部bootstrapを使ってます。)

これで実行してみるとこんな感じになります。

このように、大きめの部品はprojectにまとめていきます。

utility:ちょっとした装飾

上の例で、「1位」の文字だけ赤文字にしたいとします。
普通にcssをやっている方ならこんな方法が思い浮かぶかもしれないですね。

  • nth-childなどを使って指定する
  • 新しくクラスを作る

ただ、nth-childを使うとちょっと複雑になりますし、文字色のためだけにクラスを作るのも気が引けます。

そこで使うのがutilityです。

Bootstrapで見ると分かりやすいんですが、文字色を青にする場合text-primaryクラスに付けるだけでOKです。

こんな感じで、「文字色を青にする」や「余白を15px広げる」という1つだけの機能を持ったクラスをutilityにまとめていきます。

今回の例では、_text-red.scssをつくって以下を書きます。


.u-text-red {
    color : tomato;
}

そして、htmlのランキング最初の要素にこのクラスをつけます。


<div class="c-box-content">
    <div class="c-box-content__img"><img src="dist/img/TSU1994064_TP_V4.jpg" alt=""></div>
    <h2 class="c-box-content__title u-text-red">1位!!</h2> <!-- ←このh2タグにu-text-redをつける -->
    <p class="c-box-content__description">やった1位!</p>
</div>

こうすると「1位」の文字だけ色が赤に変わります。

このように、ちょっとした装飾をするために使われるのがutilityの部分です。

以上でFLOCSSの各カテゴリーを見てきました。後はちょっとだけ補足です。

クラス名の書き方

クラス名の書き方なんですが、MindBEMdingという方式を取り入れてます。


{接頭語}-{ブロック}__{要素}--{装飾}

先ほどのボタンの例を見るとこういう記法を使っているのが分かります。


<div class="c-box-content"> <!-- c-が接頭語、box-contentがブロック -->
    <div class="c-box-content__img"><img src="dist/img/TSU1994064_TP_V4.jpg" alt=""></div> <!-- imgが要素 -->
    <h2 class="c-box-content__title u-text-red">1位!!</h2> <!-- titleが要素 -->
    <p class="c-box-content__description">やった1位!</p> <!-- descriptionが要素 -->
</div>

このようにすることで各要素の意味が分かりやすくなったり、後の修正にも使えます。

ここでは装飾が出てきませんでしたが、例えば「1位!!」を赤文字にしようとu-text-redを使いましたが、代わりにc-box-content__title--redを用意してあげることで赤文字にすることができます。


// _ranking.scss
.p-ranking {
    background: #ececec;
    &__content {
        @include flex
       &__title { //追加
           &--red {
               color : tomato;
           }
        }
    }
}

<div class="c-box-content">
    <div class="c-box-content__img"><img src="dist/img/TSU1994064_TP_V4.jpg" alt=""></div>
    <h2 class="c-box-content__title--red">1位!!</h2> <!-- 変更 -->
    <p class="c-box-content__description">やった1位!</p>
</div>

layoutとprojectの違い

「大きな部品をまとめる」という意味ではlayoutとprojectは似ていますが、この2つは使い分けます。

  • layout : 全サイトに共通(ヘッダーとかフッターとか)
  • project : 一部のページで使う

layoutはほとんど書くことがありませんが、projectは量が多くなることが一般的です。

componentとprojectの違い

また、componentとprojectも似ているので混乱しそうですが、ここも明確に違いをつけましょう。

  • component: どのページでも使える部品。固有の意味は持たない
  • project: 一部のページで使う部品。固有の意味を持つ

例えばc-buttonc-box-contentはあらゆる場所で使えます。
また、これらに特定の意味は持っていません。言い換えれば使い方次第で意味が変わります。

c-buttonはリンクやフォームのボタンに使えますし、c-box-contentは記事一覧、ランキング、モーダルウィンドウなどに
使えます。

一方p-rankingはあまり使いまわしができません(頑張ればできるけど)。
「ランキングを表示する」というためにしか使われないからです。

これは言い換えれば「ランキングを表示する」という特定の意味を持っています。

現実世界に例えるなら、「人間」「ネクタイ」「スーツ」がcomponentで、これらを組み合わせると「ビジネスマン」というprojectができます。

超ざっくり言えば「projectは複数のcomponentで成り立つよ」です。

まとめ:CSSSは重要です

ということで以上です。やってみて分かったと思いますが非常に整理されていますよね。
1つのファイルのコード量が減りましたし、機能別にファイルを分けているので修正も容易です。
クラス名に迷うことも無くなります。

大きなものを作ったり複数人でやる場合はこうした設計が生きてくるので活用してください。

それでは、良い1日を過ごしましょう。

スポンサードサーチ

オススメ英語学習用SNS "Our Dictionary"

人気記事英語学習用SNSをLaravelで作ってみた【システム解説あり】