聞いたら一生の宝,プログラミングの基礎の基礎

第9回 CSS設計の基礎を見直す

この記事を読むのに必要な時間:およそ 4 分

詳細度によるスタイルの上書きを多用している

詳細度とはCSSプロパティを適用させる上での優先度のことで,詳細度が高いセレクタのプロパティが優先的に見た目に影響します。各セレクタの詳細度は,高い順に並べると以下のようになります。

  • !important
  • style属性に記述されているCSS
  • IDセレクタ
  • classセレクタ・属性セレクタ・擬似クラス
  • 要素セレクタ・擬似要素
  • ユニバーサルセレクタ

例として,#contentに含まれるpタグに対して,文字色をグレーにするスタイル指定を行います。

p {color: black;}
#content p {color: gray;}
<p>黒にしたいテキスト</p> <!-- 表示:黒 -->
<div id="content">
    <p>グレーにしたいテキスト</p> <!-- 表示:グレー -->
</div>

pタグには元々黒色にするような指定を行っていたので,#contentというIDセレクタを用いることで詳細度を上げて上書き対応しました。

そして数日経った後,新しい意図としてredという文字色を赤くするための汎用クラスを定義し,contentIDの中のpタグに適用させました。

.red {color: red;}
<p>黒にしたいテキスト</p> <!-- 表示:黒 -->
<p class="red">赤にしたいテキスト</p> <!-- 表示:赤 -->
<div id="content">
    <p class="red">赤にしたいテキスト</p> <!-- 表示:グレー -->
</div>

ところが,赤いテキストを期待する箇所が#contentに含まれるpタグのみグレーで表示されていました。

プロジェクトが長期的に運用され,CSSファイルが増える・長くなるとこういった不具合が散見するようになってきます。この現象を未然に防ぐためには可能な限り詳細度による上書きを行わず後述する「コンポーネント化」を行うと効果的です。

teratailで,詳細度に対して言及されているQ&Aがございましたので紹介いたします。

参考:cssを指定しやすいhtmlのidの付け方
https://teratail.com/questions/19872

キーワードは「コンポーネント化」

CSSは,今紹介した通り記述が全てグローバルなスコープとなります。よって,CSSが巨大になっていくほどに影響範囲の特定・管理が難しくなり,さまざまな不具合を引き起こす原因になってしまいます。

このリスクを回避するために効果的な手段として,CSSがもつ役割を特定の機能や見た目に限定する形で,細かく 「分離」 するというものがあります。これを「コンポーネント化」と呼びます。

たとえば,Webサイトにおいて使用頻度が高いであろう「ボタン」を例に取ると,⁠問い合わせ」「購入する」ボタンがあったとします。コンポーネントの概念を取り入れた場合,⁠ボタンであることを表す」⁠問い合わせボタンであることを表す」⁠購入するボタンであることを表す」ためのCSSに分離し,依存関係の無いようにします。

図1 ⁠ボタン」のコンポーネント化のイメージ

図1 「ボタン」のコンポーネント化のイメージ

図1のように「共通化できるCSS」「固有の属性を持つCSS」が生まれるので,上手く使えば変更に強いメンテナブルなCSSが書けそうですよね。このような分離の考え方は,オブジェクト指向CSS(以下OOCSS)と呼ばれています。

OOCSS

OOCSSでは,⁠構造(structure)と見た目(skin)の分離」⁠コンテナー(container)と内容(content)の分離」という2つの基本概念があります。

構造(structure)と見た目(skin)の分離

「構造」はインターフェースが持つ不変的な形を定義し,⁠見た目」はそのまま,その都度変わる固有の見た目を定義します。

先ほどの「ボタン」の例のように,繰り返して定義されるような決まった構造を持つものはその都度見た目と一緒に記述するのではなく分離させてCSSを書きます。

<a class="button button-contact">お問い合わせ</a>
/* ボタンの共通プロパティ */
.button {
    border-radius: 3px;
    box-shadow: 0 1px 1px 0 rgba(0,0,0,.14),0 2px 0px -3px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);
    text-align: center;
}

/* お問い合わせボタン固有のプロパティ */
.button-contact {
    background-color: blue;
}

コンテナー(container)と内容(content)の分離

HTML要素や構造,コンポーネントが存在する「場所」に依存しないCSSを実現するための概念です。CSSに対応するHTMLがどのタグだったとしても,同じ見た目を提供できるようにしましょう。

h1 {...}

上のように要素セレクタを限定して書いてしまうことはせず,次のようにすることでHTMLタグの変更がある度に見た目が変わってしまうというリスクが軽減されます。

先述のアンチパターン「HTMLの構成に依存するCSS」は,こういったルールを設けることで回避することができます。

.title {...}

また,コンポーネントは「どの場所にあるか」という依存性のあるプロパティは分離すべきです。たとえばメインカラムとサイドカラムの中のテキストリンクを指定すべく下記のようにして書くことは良い設計とは言えません。

#mainColumn .textLink {
    color: blue;
    text-decoration: underline;
}
#sideColumn .textLink {
    color: blue;
    text-decoration: underline;
}

次のようにすることで,場所にとらわれること無く再利用をすることができ,不要な記述をせずに済みます。

.textLink {
    color: blue;
    text-decoration: underline;
}

当然のように思われるかもしれませんが,CSSのファイルが増えたり,テキストリンクのスタイルケースが増えていったりすると,詳細度を上げるべく場所の指定を行ってしまうことが実際にあります。こういった不具合になり得る小さなものまで普段からチェックしておきたいものですね。

最後に

いかがでしたでしょうか。今回はCSSを書くにあたって⁠後で困らない⁠ために,基本的な設計の考え方を具体的な例を交えながら紹介いたしました。

ただ,ここで本当に重要なのはこれらの概念を覚えることではありません。実際のプロジェクトチームの中で議論し,長期的にCSSとどうやって向き合っていくかということに対してメンバー間の共通の意識を持ちつつ,実践することだと思っています。今回紹介した概念をひとつのアイデアとして「自分たちに合ったCSS設計」をガイドラインなどのドキュメントに起こし,運用できる体制をとってみてはいかがでしょうか。

著者プロフィール

平井優(ひらいゆう)

レバレジーズ株式会社 teratail開発デザイナー。

UIデザイン・情報デザインを中心に,サービス企画・フロントエンドの開発・Webに限らずポスターやステッカーなどの制作も担当。趣味はものづくりと音楽活動。特技は妄想。常々,二次元へ行きたいと本気で願っている。