横並びカードのCSSはどう設計する?具体例で理解するCSS設計の手順

HTML/CSS

CSSの基本的な文法を理解していれば、デザイン通りの画面は作成できます。
しかし何も考えずに実装をすると、拡張性がなかったりメンテナスしにくかったりするCSSとなってしまいます。

「よいCSS設計」には以下の4つの特徴があります。1

  • 予測できる
  • 再利用できる
  • 保守できる
  • 拡張できる

特にWebサービスのように複数画面のあるサイトのCSSを作成する場合は、再利用しやすい形でCSS設計をしておくことで効率的に開発ができますし、Webサイトのデザインの統一感も図れます。

今回はよいCSS設計にするためのCSS実装手順について具体例をもとに紹介します。

今回実装するデザインについて

今回は、ランディングページなどでよく見かける『横並びのカードレイアウト』を具体例として利用します。
以下のように、3つの料金表が並んだデザインの実装をゴールにします。

CSS設計の手順

CSS設計の手順は以下の通りです。

  1. デザインを『レイアウト』と『UIパーツ』に分類する
  2. 分類した要素ごとにCSSの実装をする
  3. レイアウトにUIパーツを組み込む

以下ではそれぞれの手順について紹介していきます。

デザインを『レイアウト』と『UIパーツ』分類する

CSS設計をする上で重要なのが、デザインの構成要素を『レイアウト』と『UIパーツ』に分類することです。

レイアウトとUIパーツのCSSを同じクラスに混在させないことでUIパーツの使い回しが容易になるため、管理がしやすいCSS設計となります。

今回の例をレイアウトとUIパーツに分ける場合、以下の3つの要素に分類できます。

  • 料金エリアのレイアウト(画面全体のレイアウト)
  • 料金表のレイアウト(UIパーツ同士のレイアウト)
  • 『料金表』というUIパーツ

分類した要素ごとにCSSの実装をする

レイアウトとUIパーツごとにHTML・CSSを実装します。
なお、今回のCSS設計では手法にBEMを採用します。

料金エリアのレイアウト(画面全体のレイアウト)

料金エリア(ピンク色の部分)はヘッダ(水色の部分)とボディ(緑色の部分)で構成されています。

BEMで表現すると、エリアがblock、ヘッダとボディがelementとなります。

画面全体のレイアウトに関するHTMLとCSSは以下の通りです。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://unpkg.com/css-wipe/reset.css" />
    <link href="css/price-area-layout-hoge.css" rel="stylesheet" type="text/css">
  </head>
  <body>
    <div class="price-area">
      <h2 class="price-area__header">
        price-area__header
      </h2>
      <div class="price-area__body">
        price-area__body
      </div>
    </div>
  </body>
</html>
/* ------------------------------
price-area
------------------------------ */
.price-area {
  background-color: lightcoral;
  padding: 15px 30px;
  width: 1080px;
  max-width: 100%;
  margin: 0 auto;
}

.price-area__header {
  background-color: lightblue;
  font-size: 35px;
  margin-bottom: 20px;
  padding: 10px 0px;
  border-bottom: 1px solid #ddd;
}

.price-area__body {
  background-color: lightgreen;
}

料金表のレイアウト(UIパーツ同士のレイアウト)

料金表が3つ横並びになっているので、横並びのレイアウトに関するCSS設計をします。

料金表のレイアウト(ピンク色の部分)は3つの料金表(水色の部分)で構成されています。

BEMで表現すると、料金表を配置する箇所がblock、料金表がelementとなります。

料金表のレイアウトに関するHTMLとCSSは以下の通りです。
今回はflexboxを利用してブロック要素(料金表)を横並びにしました。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://unpkg.com/css-wipe/reset.css" />
    <link href="css/price-box-layout-hoge.css" rel="stylesheet" type="text/css">
  </head>
  <body>
    <div class="price-boxes">
      <div class="price-boxes__item">
        price-boxes__item
      </div>
      <div class="price-boxes__item">
        price-boxes__item
      </div>
      <div class="price-boxes__item">
        price-boxes__item
      </div>
    </div>
  </body>
</html>
/* ------------------------------
price-boxes
------------------------------ */
.price-boxes {
  background-color: lightcoral;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.price-boxes__item {
  background-color: lightblue;
  flex: 1;
  margin-right: 2.43902%;
}

.price-boxes__item:last-child {
  margin-right: 0;
}

『料金表』というUIパーツ

料金表はヘッダ(水色の部分)、タイトル(緑色の部分)、ボディ(灰色の部分)、価格表示(ピンク色の部分)、説明文(黄色の部分)で構成されています。

料金表のHTMLとCSSは以下の通りです。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://unpkg.com/css-wipe/reset.css" />
    <link href="css/price-box-hoge.css" rel="stylesheet" type="text/css">
  </head>
  <body>
    <div class="price-box">
      <div class="price-box__header">
        <div class="price-box__title">price-box__title</div>
      </div>
      <div class="price-box__body">
        <p class="price-box__price">price-box__price</p>
        <p class="price-box__description">price-box__description</p>
      </div>
    </div>
  </body>
</html>
/* ------------------------------
price-box
------------------------------ */
.price-box {
  background-color: lightcoral;

  border: 1px solid #ddd;
}

.price-box__header {
  background-color: lightblue;

  padding: 30px 15px;
  border-bottom: 1px solid #ddd;
}

.price-box__title {
  background-color: lightgreen;

  font-size: 20px;
  font-weight: bold;
}

.price-box__body {
  background-color: lightgrey;

  padding: 40px 15px;
}

.price-box__price {
  background-color: lightpink;

  font-size: 18px;
  font-weight: bold;
  margin-bottom: 25px;

}

.price-box__description {
  background-color: lightyellow;
}

UIパーツのCSS設計では、UIパーツを使い回しのしやすい形にすることが重要です。
具体的には、UIパーツの外に作用するCSS(marginなど)はUIパーツのCSSで定義しないようにします。

marginをUIパーツのCSSに定義しないことでレイアウトの中にUIパーツがぴったり埋め込まれる形になるため、UIパーツの再利用性が高まります。

デザインのどの箇所をUIパーツとして定義したらよいか分からない場合は「デザインを使い回すとしたらどういった単位(パーツ)になるのか」を考えるとUIパーツを見つけやすいです。

レイアウトにUIパーツを組み込む

レイアウトとUIパーツを作成できたら、それぞれのHTML・CSSを組み合わせます。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://unpkg.com/css-wipe/reset.css" />
    <link href="css/simple-price-boxes.css" rel="stylesheet" type="text/css">
  </head>
  <body>
    <div class="price-area">
      <h2 class="price-area__header">
        料金一覧
      </h2>
      <div class="price-area__body">
        <div class="price-boxes">
          <div class="price-boxes__item price-box">
            <div class="price-box__header">
              <div class="price-box__title">FREE</div>
            </div>
            <div class="price-box__body">
              <p class="price-box__price">無料</p>
              <p class="price-box__description">無料で使えるプランです。料金を気にせずサービスを利用できます。</p>
            </div>
          </div>
          <div class="price-boxes__item price-box">
            <div class="price-box__header">
              <div class="price-box__title">STANDARD</div>
            </div>
            <div class="price-box__body">
              <p class="price-box__price">1,000円/月</p>
              <p class="price-box__description">一般的なプランです。お手頃な価格でサービスを利用できます。</p>
            </div>
          </div>
          <div class="price-boxes__item price-box">
            <div class="price-box__header">
              <div class="price-box__title">PRO</div>
            </div>
            <div class="price-box__body">
              <p class="price-box__price">3,000円/月</p>
              <p class="price-box__description">フルスペックのプランです。サービスの全ての機能を利用できます。</p>
            </div>
          </div>
          <div class="price-boxes__item price-box">
            <div class="price-box__header">
              <div class="price-box__title">PRO+</div>
            </div>
            <div class="price-box__body">
              <p class="price-box__price">10,000円/月</p>
              <p class="price-box__description">新しく追加されたフルスペックのプランです。個別サポートにも対応しております。</p>
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>
/* ------------------------------
price-area
------------------------------ */
.price-area {
  padding: 15px 30px;
  width: 1080px;
  max-width: 100%;
  margin: 0 auto;
}

.price-area__header {
  font-size: 35px;
  margin-bottom: 20px;
  padding: 10px 0px;
  border-bottom: 1px solid #ddd;
}

.price-area__body {
}

/* ------------------------------
price-boxes
------------------------------ */
.price-boxes {
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.price-boxes__item {
  flex: 1;
  margin-right: 2.43902%;
}

.price-boxes__item:last-child {
  margin-right: 0;
}

/* ------------------------------
price-box
------------------------------ */

.price-box {
  border: 1px solid #ddd;
}

.price-box__header {
  padding: 30px 15px;
  border-bottom: 1px solid #ddd;
}

.price-box__title {
  font-size: 20px;
  font-weight: bold;
}

.price-box__body {
  padding: 40px 15px;
}

.price-box__price {
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 25px;

}

.price-box__description {
}

すべて組み合わせると以下のようになります。

参考: UIパーツを再利用してみる

たとえば、料金表のデザインを横3列から4列に変更するとします。
その場合、UIパーツを追加するだけで横4列のデザインが完成します。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://unpkg.com/css-wipe/reset.css" />
    <link href="css/simple-price-boxes.css" rel="stylesheet" type="text/css">
  </head>
  <body>
    <div class="price-area">
      <h2 class="price-area__header">
        料金一覧
      </h2>
      <div class="price-area__body">
        <div class="price-boxes">
          <div class="price-boxes__item price-box">
            <div class="price-box__header">
              <div class="price-box__title">FREE</div>
            </div>
            <div class="price-box__body">
              <p class="price-box__price">無料</p>
              <p class="price-box__description">無料で使えるプランです。料金を気にせずサービスを利用できます。</p>
            </div>
          </div>
          <div class="price-boxes__item price-box">
            <div class="price-box__header">
              <div class="price-box__title">STANDARD</div>
            </div>
            <div class="price-box__body">
              <p class="price-box__price">1,000円/月</p>
              <p class="price-box__description">一般的なプランです。お手頃な価格でサービスを利用できます。</p>
            </div>
          </div>
          <div class="price-boxes__item price-box">
            <div class="price-box__header">
              <div class="price-box__title">PRO</div>
            </div>
            <div class="price-box__body">
              <p class="price-box__price">3,000円/月</p>
              <p class="price-box__description">フルスペックのプランです。サービスの全ての機能を利用できます。</p>
            </div>
          </div>
+         <div class="price-boxes__item price-box">
+           <div class="price-box__header">
+             <div class="price-box__title">PRO+</div>
+           </div>
+           <div class="price-box__body">
+             <p class="price-box__price">10,000円/月</p>
+             <p class="price-box__description">新しく追加されたフルスペックのプランです。個別サポートにも対応しております。</p>
+           </div>
+         </div>
        </div>
      </div>
    </div>
  </body>
</html>

このように、使い回しのしやすいUIパーツを作成することで拡張性の高いCSSになっていることがわかります。

まとめ

よいCSS設計をするために意識するポイント
  • デザインをレイアウトとUIパーツに分類する
  • UIパーツのCSSは再利用しやすい形に設計する
  • レイアウトとUIパーツのCSSは同じクラスに混在させない

デザインをもとにHTML/CSSの実装はできるけど、正しい実装なのか自信がない」「巷で人気のHTML/CSS本だと内容が初心者向きすぎて物足りない」といった方は『CSS設計』というキーワードをもとに参考書を探すとよいでしょう。

個人的には、CSS設計の参考書はCSS設計完全ガイド ~詳細解説+実践的モジュール集
がオススメです。

自分はバックエンドメインで仕事をしてきたので、CSS設計については自信がなかったのですが、CSS設計完全ガイド ~詳細解説+実践的モジュール集のおかげでマークアップに対する苦手意識を克服できました。

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!