雑に学ぶCSS設計


はじめに

上司「味噌くん。しばらくコロナでお仕事無いから。」

新人1年目僕(

    経験積めない
       ↓
 最悪、転職(真っ白な経歴書)
       ↓
    こりゃまずい

)

仕方ないから、Qiitaでポートフォリオを増産するか。 ←今ここ

本題のちょっと前の話

ReactでWeb開発する僕「うっ...個人開発初心者特有の汚いコードを書いてしまった。」

個人開発によって生まれた汚いコード ← 何とかせねば

僕「TypeScriptコードはlinterとprettierである程度はコーディング規則を整理できるけど、CSSってどう書けばいいのさ。」

今回は、CSSの設計手法に関して調べた内容を書いていこうと思います。

CSSとは

CSS(Cascading Style Sheets)とはHTMLやXMLような文章を構造化して記述するマークアップ言語に対して、色やフォントなどのスタイルを整えるためのスタイルシート言語です。
HTMLはCSSを読まずとも、styleタグやstyle属性を使うことでスタイルを指定することができます。しかし、肥大化していくWebページに特定箇所のみにスタイルを適用するような書き方を行い、無駄に行数を増やすのは得策ではありません。そのため、HTMLやXMLは文章構造を担い、CSSはスタイルを担うように分離してWeb開発を行うことが一般的です。

肥大化するページとCSSの複雑化

さて、時代とともにWebページのコンテンツが充実し、タブレットやスマホなどでレイアウトが異なるレスポンシブデザインやアニメーションが見られるようになりました。ところが、CSSはグローバルスコープしか持たないため、スタイルを重複しない命名で指定しなければなりません。そのため、開発現場ではページ自体の肥大化と開発人員の増加が相まって、CSSは複雑化し、保守性や拡張性を劣化しました。そこで、この問題を解決するためにCSS設計についていくつかの手法が生まれました。

CSS設計

まず前提として、CSS設計はどれが一番優れているといった比較はできません。あくまで、設計における手法・思想であり、プログラミングパラダイムやフレームワークのように開発環境や好みに応じて使い分けてください。それを踏まえたうえで、以下のCSS設計の紹介をさせてもらいます。

  • SMACSS
  • OOCSS
  • BEM

また、我流で書いている部分もあるので良いと思ったものを取り入れてもらえると嬉しいです。

SMACSS

詳しい内容は「Scalable and Modular Architecture for CSS」で紹介されていますので、この記事では紹介されていた例とともに、かいつまんで説明していきます。
SMACSS(Scalable and Modular Architecture for CSS)はスタイルの対象に関して以下の5つのパターンに分類することを基本とします。

  • Base

<html>や<body>、<form>といった単独の要素や属性(IDやクラスを扱わない)

html, body, form { margin: 0; padding: 0; }
input[type=text] { border: 1px solid #999; }
a { color: #039; }
a:hover { color: #03C; }
  • Layout

ページ内で分割された1つ以上のModuleを持つセクション

#header, #article, #footer {
    width: 960px;
    margin: auto;
}

#article {
    border: solid #CCC;
    border-width: 1px 0 0;
}
  • Module

再利用可能なパーツ

.module > h2 {
    padding: 5px;
}

.module span {
    padding: 5px;
}
  • State

ドロップダウンやサイドメニューの表示非表示やコンポーネントの拡大縮小、コンポーネントが利用可能かなどのLayoutとModuleの状態

<!-- CSSを適用する対象要素 -->
<div id="header" class="is-collapsed">
    <form>
        <div class="msg is-error">
            There is an error!
        </div>
        <label for="searchbox" class="is-hidden">Search</label>
        <input type="search" id="searchbox">
    </form>
</div>
.tab {
    background-color: purple;
    color: white;
}

.is-tab-active {
    background-color: white;
    color: black;
}
  • Theme

文字色や画像定義、表示言語などのサイト上で見えるもの


.mod {
    border: 1px solid;
}

.mod {
    border-color: blue;
}

また、SMACSSでは命名規則に関しても言及しています。例えば、Layoutには"l-"や"layout-"、Stateには"is-"のようにスタイルのパターンごとに異なったものにします。これにより、CSSが複数ファイルに分割されようとスタイルがどのパターンで指定されているか、どのファイルに属しているか簡単に推察することができます。

OOCSS

OOCSS(Object Oriented CSS)は「構造と見た目を分離する」ことを目的としたCSS設計手法です。
例えば、横並びのボタンを考えてください。

<button class="btn save-btn">
    <font>save</font>
</button>

<button class="btn load-btn">
    <font>load</font>
</button>
/* 構造のみを書く */
.btn{
    float: left;
    text-align: center;
}

/* 見た目のみを書く */
.load-btn{
    background-color: #248;
    color: #fff;
}

多くのWebサイトではボタンやフォームといったものが並んでいる場合、サイズは同じであることが多いです。そして、各部品を区別するために色やアイコンを使っています。
OOCSSでは、同じサイズつまり同じ構造を繰り返し使い、色やアイコンなどの見た目を各部品に適用できるようなCSSの書き方を推奨する設計手法です。

BEM

BEMは以下の3つの要素からなる設計手法です。名前の由来もその頭文字を取っています。

  • Block

何かしらのかたまり ヘッダーやフッター、検索バー

  • Element

Block内の要素(必ずBlock内に存在しなければならない) 検索バーにおける入力フォームと検索ボタン

  • Modifier

修飾 BlockまたはElementに対する見た目や状態

また、命名規則に関しては他の2つと異なり、MindBEMdingという以下の書き方にします。

block__element--modifier

雑ですが、例を作りました。
※classは1つ指定(シングルクラス)とするのが基本らしいのですが、個人的に必要はないかなって思っています。

<form action="#" method="post">

    <div class="content">
        <p>名前:
            <br>
            <input class="content__input" type="text" name="name">
        </p>
    </div>

    <div class="content">
        <p>mail:
            <br>
            <input class="content__input" type="text" name="mail">
        </p>
    </div>

    <div class="content">
        <p>phone(任意):
            <br>
            <input class="content__input content__input--orange" type="text" name="phone">
        </p>
    </div>

</form>
    .content{
        display: flex;
        align-items: center;
        justify-content: left;
    }
    .content__input{
        border-radius:3px;
        border: 2px solid #0FF;
    }
    .content__input--orange{
        border: 2px solid #ffCC00;
    }

BEMは長い命名規則を持ってしまうことが問題として挙げられますが、シングルクラスや強い命名規則は長い目で見ても高いメンテナンス性を保証します。