【付録・CSS設計3】4つのゴールと8つの考え方【WPテーマ作成】

WordPressテーマ作成

本付録は、メインシリーズであるWordPressのテーマ作成に役立ちそうな情報を補足していくパートだ。

前回は、リセットCSS英単語の結合方式について解説した。

特に重要なのはリセットCSSで、これもまだ具体例がなく分かりづらいかもしれない。

とりあえず、そんな感じで考えるのか、という雰囲気だけでも知っておいてもらえればOK。

今後WordPressのCSSを作る時には、自分なりに考えてその理由なんかも書くつもりなので、その時まで今しばらくお待ちいただきたい。

以下がその記事だ。

さて、ようやく今回からCSS設計の内容に入っていく…が、具体的な手法ではない。

それらの手法で共通した考え方を解説していこう。

前半では、CSS設計によって実現したい4つのゴールを解説する。

後半で、そのゴールを実現するための8つの考え方を見ていこう。

具体的なサンプルも用意するので、それで感覚を掴んでいってもらいたい。

なお、本付録は以下の本を参考にしている。

https://amzn.to/3vhFAqe

気になる方は、実際に本屋で中身を見てみたり、買ってみたりしよう。

スポンサーリンク

CSS設計が目指す4つのゴール

まずはこちらから。

初回で、CSS設計はCSSを組みやすく、また管理しやすくするものだ、ということを書いた。

が、これもまだ抽象的で分かりづらい。

そこで、より具体的にどんなことを目指しているのかというのが4箇条で挙げられている。

それが、以下の4つだ。

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

CSS設計完全ガイド ~詳細解説+実践的モジュール集

それぞれ、詳細を見ていこう。

予測できる

これには、さらに二つの意味が含まれている。

一つは、その設定が期待通りに動くか

もう一つは、その設定の影響範囲が分かるか

つまり、新たな設定の追加や既存の設定の変更があっても、それが予想外なところへ影響しないことを表している。

他の内容もそうだが、大規模なページを作る際には必須だろう。

再利用できる

これも大規模になれば是非満たしたい条件だ。

ページ内にある部品について、それを別のところでも使いたいとしよう。

そのとき、変にコードを書き直したり、新たなスタイルを追加したりといったことがないのが、この再利用できるという状態だ。

これをするためには、その部品に対して適切な抽象化分離を行う必要がある。

このあたりは難しいと思うので、本記事の後半や今後解説する具体的な設計手法の中で理解していくようにしよう。

保守できる

新しい内容を追加したり、あるいは配置を変えたりなどを行っても、既存のCSSを書き換える必要が無い状態のこと。

一つ目の予測できると似た内容だ。

あくまで私の解釈だが…一つ目は既存の設定から見た変更対象への予想外な影響がないこと、こちらはその変更対象から見た他の既存の設定への予想外な影響がないこと、という感じだろうか。

まあ、結局は両方とも互いに意図しない影響を与えないこと、という認識でもいいかもしれない。

拡張できる

この拡張は、機能の話ではない。

機能的な拡張は、どちらかというと一つ上の保守できるに含まれるだろう。

最初は一人で作っていたものが、だんだん規模が大きくなってくると複数人数のチームで作るようになる、なんてこともある。

その時でも問題なく管理できる、というのがこの拡張の意味だ。

以上、4項目がCSS設計の目指すゴールになる。

8つの考え方

さて、ゴールが少しだけ具体的になったが、まだかなり分かりづらいと思う。

また、これを目指してやろう、といきなり書き始めるのも難しいだろう。

そこで、各ゴールを実現するために気を付けるべき8つの考え方も提示されている。

1.特性に応じてCSSを分類する
2.コンテンツとスタイリングが疎結合である
3.影響範囲がみだりに広すぎない
4.特定のコンテキストにみだりに依存していない
5.詳細度がみだりに高くない
6.クラス名から影響範囲が想像できる
7.クラス名から見た目・機能・役割が想像できる
8.拡張しやすい

CSS設計完全ガイド ~詳細解説+実践的モジュール集

このそれぞれの詳細を見ていく…のだが、実際にサンプルを用意してそのソースコードを直しながら見ていこう。

このサンプルについて、HTMLの中身に書いてあるテキストや画像は異なるが、HTML自体の構造やID、クラス名といった属性、またCSSの中身はそのまま参考書のものを引用している。

想定としては、ブログなどで埋め込む一つの部品に対して手を加えていく

なお、この1部品のことを本シリーズではモジュールと呼ぶ。

リセットCSSは、前回書いた通りcss-wipeを使う。

ちょっとCDNが見つからなかったので、css-wipe.cssという名前をつけたファイルを用意し、最初に読み込むことにする。

また、自作のCSSも同じようにファイルで読み込もう。

初期段階のソースコードは以下の通り。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>第3回CSS設計サンプルページ</title>
        
        <!-- css-wipeのファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/css-wipe.css">

        <!-- 自作CSSファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">
    </head>
    <body>
        <article id="main">
            <div class="module main-module">
                <figure>
                    <img src="./image/sample.jpg" alt="写真:サンプル">
                </figure>
                <div>
                    <h2>記事タイトルテキスト</h2>
                    <p>記事本文テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト<br>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </p>
                    <h3>サブタイトル</h3>
                    <span>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </span>
                </div>
            </div>
        </article>
    </body>
</html>
@charset "UTF-8";

#main span {
    color: #555;
    font-size: 14px;
}

#main div.module.main-module {
    /* 左右中央揃えのための指定 */
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-family: sans-serif;
    font-size: 16px;
    line-height: 1.5;
}

#main div.module.main-module figure {
    flex: 1 1 25%;
    margin-right: 3.33333%;
}

#main div.module.main-module img {
    width: 100%;
    vertical-align: top;
}

#main div.module.main-module div {
    flex: 1 1 68.33333%;
}

#main div.module.main-module h2 {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

#main div.module.main-module h3 {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

なお、css-wipeは公式のものをそのまま使っているので、ソースの記載は省略する。

また、style.cssも一か所だけ参考書と異なり、先頭にcharset "UTF-8";を追加した。

単に文字化け防止なので、あまり気にしなくていい。

では、8項目それぞれの詳細を見ていこう。

特性に応じてCSSを分類する

一つ目はこれ、CSSの各記述を役割や特性によって分類していく

例えば…

  • リセットCSSや、例えば「リンクの文字を変える」、「フォントはこれにする」といったサイト全体の下地となるベースグループ
  • ヘッダー、メインのコンテンツ領域、フッターといったレイアウトグループ
  • モジュールに関わるモジュールグループ

など、色々な分け方が考えられる。

この分け方は設計手法によっても異なり、それぞれはその時に見ていこう。

今回は、今出した3つに分けることを考えてみる。

このグループへ分けたとき、クラスへ入れたモジュール名の前に接頭語をつけて目印にすることも多い

例えば、レイアウトを指定する場合は、l-ly-といったものをつける、という感じだ。

ここもそれぞれの設計手法によって推奨する形が異なる。

これらを踏まえ、サンプルソースを見てみよう。

この中で、フォントを指定している記述があるのが分かると思う。

#main div.module.main-module {
    /* 左右中央揃えのための指定 */
    /* 省略 */
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-family: sans-serif; /* ←これ */
    font-size: 16px;
    line-height: 1.5;
}

ここで設定しているフォントだが、通常はページ全体で共通の内容だろう。

そのため、こういった内容はベースグループに該当し、bodyタグに書くことにしてみる。

つまり、今の行を削除し、新たに…

body {
    font-family: sans-serif;
}

このブロックを追加する。

これで、サイト全体のフォントがここで設定されるようになり、個別で設定する必要が無くなった。

また、もし全体のフォントを変更したいとなった場合にも、この1か所を直せばいいことになる。

さて、他に分けられそうなものが無いか見てみると…

#main div.module.main-module {
    /* 左右中央揃えのための指定 ←これ*/
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
    /* モジュールに対する指定 */
    /* 省略 */
}

この、大きさや余白の調整をしている部分。

今、仮定としてここはブログ等で使う一つのモジュールだ。

もし他にモジュールがあったとすると、今の書き方ではそちらに対してもこの5行を書かなければいけない

それだと手間なので、これも切り出してみよう。

ここはレイアウトグループとして分類する。

新しくクラスly-contを作り、このモジュールではなく一つ上のモジュールを含む枠であるarticleタグにクラスを付与しよう。

<!-- 省略 -->
<article id="main" class="ly-cont"> <!-- クラス名を追加 -->
    <!-- 省略 -->
</article>
<!-- 省略 -->

そして、CSS側では注目していた5項目の設定を切り出し、今作ったly-contクラスに設定するよう変更する。

.ly-cont {
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

これにより、新しくモジュールを追加したとしても、横幅の設定はここで使えばよくなった

もちろん横幅を変更したい場合も1か所だけの修正で済むし、さらに接頭語でly-とつけたのでこのクラスがレイアウトを担当しているというのもぱっと見で分かるようになった。

さて、オマケでもう一つ。

今、moduleクラスで一つのモジュールを作っている。

これは例だからこういう名前をつけているだけであって、通常はそのモジュールを表すクラス名がつけられる。

これにも、接頭語をつけてモジュールであることを分かりやすくしよう、という設計手法もある。

それに倣い、ブロックであることを表すbl_を追加しておこう。

なお、もう一個あるmain-moduleクラスは後で見るので、一旦放置する。

これで一つ目の項目におけるリファクタリングが終わるので、それぞれ全体をもう一度載せておく。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>第3回CSS設計サンプルページ</title>
        
        <!-- css-wipeのファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/css-wipe.css">

        <!-- 自作CSSファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">
    </head>
    <body>
        <article id="main" class="ly-cont">
            <div class="bl_module main-module">
                <figure>
                    <img src="./image/sample.jpg" alt="写真:サンプル">
                </figure>
                <div>
                    <h2>記事タイトルテキスト</h2>
                    <p>記事本文テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト<br>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </p>
                    <h3>サブタイトル</h3>
                    <span>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </span>
                </div>
            </div>
        </article>
    </body>
</html>
@charset "UTF-8";

/* === ベース === */
body {
    font-family: sans-serif;
}

/* === レイアウト === */
.ly-cont {
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

/* === モジュール === */
#main span {
    color: #555;
    font-size: 14px;
}

#main div.bl_module.main-module {
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-size: 16px;
    line-height: 1.5;
}

#main div.bl_module.main-module figure {
    flex: 1 1 25%;
    margin-right: 3.33333%;
}

#main div.bl_module.main-module img {
    width: 100%;
    vertical-align: top;
}

#main div.bl_module.main-module div {
    flex: 1 1 68.33333%;
}

#main div.bl_module.main-module h2 {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

#main div.bl_module.main-module h3 {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

CSSで、それぞれのグループ分けした内容を設定する部分として3つのパートに分けるようコメントも入れてみた。

さて、ここまで見てきてお分かりの方もいらっしゃるかもしれないが、ベストプラクティスが一つ見えてきた。

それが、モジュールには自身のレイアウトに関する指定を基本的にしない、ということ。

具体的には…

  • position(static, relative以外)
  • z-index
  • top, left, right, bottom
  • float
  • width, height

などだ。

これらはそのモジュールを含む親要素に対して設定することにより、モジュール自身は横幅が自動で100%となるなど、これも調整できることになる。

これなら、そのモジュールを例えば移動しても表示が崩れるようなことは無くなるだろう。

…ただ、この状態だと複数モジュールを書いた時に上下間の余白が空かない

それについては幾つか対処法があり、色々解説が進んだ状態でやろうと思う。

コンテンツとスタイリングが疎結合である

二つ目の考え方はこれ。

疎結合という言葉が聞き馴染みのないものだと思うが、ここでは要するにHTMLに依存していない、と解釈してくれれば大丈夫だ。

まあ、それでもまだ分かりづらいと思うので、先に具体例を直してみよう。

このモジュール内、h2タグの設定をしている部分に注目してみる。

#main div.bl_module.main-module h2 {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

ここで、直接h2タグに対して設定を行っている。

今は、HTML側でもh2タグで書いているので、設定がしっかり反映されている…のだが。

ここで、HTML側の該当部分を例えばh3h4などに変えたいとなった時に、このCSS側も修正が必要になってしまう。

それを解決するために、そのh3h4などもグループセレクターで入れてしまおう。

#main div.bl_module.main-module h2,
#main div.bl_module.main-module h3,
#main div.bl_module.main-module h4 {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

なんてことはしてはいけない

これだと、元のHTML側で書かれているサブタイトル側も変わってしまうのだ。

ではどうするかというと、非常にシンプルで、要素型セレクタ―を使わなければいい

これが、HTMLに依存しなくなるということであり、イコールで疎結合になる。

要素型セレクタ―の代わりには、クラスセレクタ―を使う。

HTML側で今h2タグを使っているところにtitleh3を使っているところにsub-titleというクラス名をつける。

<div>
    <h2 class="title">記事タイトルテキスト</h2>
    <!-- 省略 -->
    <h3 class="sub-title">サブタイトル</h3>
    <!-- 省略 -->
</div>

そしてCSS側、h2h3に対して行っていた設定部分を、このクラスセレクタ―を使うよう変更する。

#main div.bl_module.main-module .title {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

#main div.bl_module.main-module .sub-title {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

これで、HTML側で見出しのレベルを変えても影響が無くなった。

このように、なるべく要素型セレクタ―を使わないというのがベストプラクティスになる。

ついでに、今色々なセレクターについているdiv.bl_module.main-moduleの先頭のdivも消してしまおう。

その他、figure要素とその直後のdiv要素も同じ方法で直しておく。

この時、figureの中に入っているimgはいいのか、と思われるかもしれないが、ここはかなり対象が絞られているので、こういった時はそのまま使ってもいい。

もう一つ、pspanはやらなくていいのかと思われるかもしれないが、ここはやるべきだ。

これらはモジュール内でもよく使われるもので、例え対象が絞られていようとクラス名をつけるべきだろう。

ただ、今pに対するスタイルは個別で設定していないので何もせず、spanは一つ後ろの解説のために残しておく。

現段階でのリファクタリングは以上なので、全体像を。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>第3回CSS設計サンプルページ</title>
        
        <!-- css-wipeのファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/css-wipe.css">

        <!-- 自作CSSファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">
    </head>
    <body>
        <article id="main" class="ly-cont">
            <div class="bl_module main-module">
                <figure class="image-wrapper">
                    <img src="./image/sample.jpg" alt="写真:サンプル">
                </figure>
                <div class="body">
                    <h2 class="title">記事タイトルテキスト</h2>
                    <p>記事本文テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト<br>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </p>
                    <h3 class="sub-title">サブタイトル</h3>
                    <span>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </span>
                </div>
            </div>
        </article>
    </body>
</html>
@charset "UTF-8";

/* === ベース === */
body {
    font-family: sans-serif;
}

/* === レイアウト === */
.ly-cont {
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

/* === モジュール === */
#main span {
    color: #555;
    font-size: 14px;
}

#main .bl_module.main-module {
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-size: 16px;
    line-height: 1.5;
}

#main .bl_module.main-module .image-wrapper {
    flex: 1 1 25%;
    margin-right: 3.33333%;
}

#main .bl_module.main-module .image-wrapper img {
    width: 100%;
    vertical-align: top;
}

#main .bl_module.main-module .body {
    flex: 1 1 68.33333%;
}

#main .bl_module.main-module .title {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

#main .bl_module.main-module .sub-title {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

さて、今回出てきていないがもう一つ疎結合に絡んだ話を。

属性セレクタ―についても、特定の値を使用するのは避けた方がいい

例えば、以下のCSS。

a[href="https://google.co.jp"] {
    /* 設定する内容 */
}

これは、リンク先がGoogleであるようなリンクに対してのスタイルを設定している。

ここで、もしYahoo!も追加したいとなったらどうなるかというと…

a[href="https://google.co.jp"],
a[href="https://yahoo.co.jp"] {
    /* 設定する内容 */
}

このように、グループセレクタ―で増やさなければいけなくなる。

こんな状態になってしまうため、極力特定の値を指すような属性セレクタ―も使わないようにしよう。

影響範囲がみだりに広すぎない

三つ目はこれ、ポイントはみだりに、というところ。

ここを強調する理由は、例えばベースグループの設定はめちゃくちゃ影響範囲が広い

しかし、そこはしっかり意図して広くしているので問題ない。

要するに、しっかり設計・考慮した上で広くなる分には、それは必要なことなので構わない。

問題となるのは、意図した以上に広い影響範囲を持つコードだ。

これが入ってしまうと、それに影響される対象については常にその設定を打ち消す記述をしなければいけなくなる。

解決のための方針は二つあり、スコープを絞るか、そもそも影響範囲の広い内容を極力書かないのいずれかだ。

今回は前者のスコープを絞る方法で見ていこう。

CSSで、以下の記載に注目する。

#main span {
    color: #555;
    font-size: 14px;
}

一つ上で残しておいたspanの設定だ。

これは、今はモジュール一つしかないので影響なさそうに見えるが、他にモジュールが入ってくるとその中のspanにも影響を与えてしまう。

今この部分で変えたいのは、サブタイトルの下にあるテキストの部分だけだ。

…本来はここはpタグを使うべきなのだろうが、説明のためあえてspanタグを使っていることに注意。

で、ここの部分を変えるためなのに、#main spanは明らかに広すぎだ。

そこで、まずは以下のように直してみる。

#main .bl_module.main-module span {
    color: #555;
    font-size: 14px;
}

セレクターに、今見ているモジュールの中、という条件を付け加えた。

これで、他のモジュールに影響を与えることが無くなり、影響範囲を狭めることができた。

…のだが、まだちょっと広いように思う。

というのも、もしメインタイトル下のテキスト内でspanタグを使いたい場合、そこにも影響してしまう。

それが意図したものであればいいのだが、今回はそれも避けてみる。

#main .bl_module.main-module .body > span {
    color: #555;
    font-size: 14px;
}

今度は子セレクタ―を組み合わせて、bodyクラスの直下にあるspanタグのみまで限定してみた。

こうすれば、メインタイトル下のテキスト内で使った場合には孫関係となり、影響しなくなる。

今やったように、なるべく直近の親要素まで含めたり、必ず直下にある場合は子孫ではなく子セレクタ―が使えないかを考えるのがポイント。

…ちなみにだが、今は説明のためにこのような書き方をしているだけで、全体で考えればここも一つ上のようにクラス名をつけるのがベストだろう。

今回の修正はここだけなので、全体を貼るのはやめておく。

特定のコンテキストにみだりに依存していない

さて、四つ目はこれなのだが、その前にコンテキストとは場所や状況のことだ。

言い換えると、モジュールの配置場所が変わった途端に動かなくなるケースがまずい、ということになる。

今回のサンプルで言えば、いたるところに#main .bl_module.main-module ○○という記述がある。

これは、mainというIDの中、そのモジュールに入っている何かに適用していることになる。

つまり、そのmain以外に動かすとスタイルが当たらなくなってしまう

これでは他の場所で同じモジュールを使う時に面倒なので、この先頭の#mainを消してしまおう。

HTMLは変化がないので、CSSだけ記載する。

@charset "UTF-8";

/* === ベース === */
body {
    font-family: sans-serif;
}

/* === レイアウト === */
.ly-cont {
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

/* === モジュール === */
.bl_module.main-module {
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-size: 16px;
    line-height: 1.5;
}

.bl_module.main-module .image-wrapper {
    flex: 1 1 25%;
    margin-right: 3.33333%;
}

.bl_module.main-module .image-wrapper img {
    width: 100%;
    vertical-align: top;
}

.bl_module.main-module .body {
    flex: 1 1 68.33333%;
}

.bl_module.main-module .title {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

.bl_module.main-module .sub-title {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

/* 下に移動 */
.bl_module.main-module .body > span {
    color: #555;
    font-size: 14px;
}

これで、他の場所でも使えるようになった。

もちろん、レイアウトはly-contクラス側でやっているので問題なく適用される。

少しずつだが、すっきりしてきた。

詳細度がみだりに高くない

では5つ目、この詳細度初回復習したカスケーディングの中の話

詳細度が変に高くなってしまうと、セレクターがぱっと見で分かりづらくなったり、他の要素に依存しやすくなったりする。

また、詳細度が高いということは適用の優先度も上がるので上書きが難しくなり、最悪!importantを使うという選択肢まで出てきてしまう。

これらが要因で、メンテナンスの工数もどんどん増えてしまうのだ。

つまり、詳細度は極力低く抑えたい

そのためには、基本的にクラスセレクタ―を使うという方針で作るのがいいだろう。

例えばIDセレクタ―はそれだけで詳細度が上がり、他にも1ページで1回しか使えないのでスタイルでこれを使うメリットはあまりない。

また、クラス名も複数指定するのが意図したものであればいいが、必要なければそれも取り除くことを検討した方がいいだろう。

今回の場合でいうと、セレクターの.bl_module.main-moduleという部分。

これには二つのクラス名を指定しているが、そもそもmain-moduleというクラスが必要なのだろうか。

main-modulemainの中のモジュールであることを表すためにつけていたが、それ固有の設定があるわけでもない。

実際、CSSの設定は全て一つのモジュールに対する設定だ。

ということは、このmain-moduleクラスが無駄なので、HTML、CSS両方から消してしまおう。

これにより、HTMLとCSSそれぞれ以下のようになる。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>第3回CSS設計サンプルページ</title>
        
        <!-- css-wipeのファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/css-wipe.css">

        <!-- 自作CSSファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">
    </head>
    <body>
        <article id="main" class="ly-cont">
            <div class="bl_module">
                <figure class="image-wrapper">
                    <img src="./image/sample.jpg" alt="写真:サンプル">
                </figure>
                <div class="body">
                    <h2 class="title">記事タイトルテキスト</h2>
                    <p>記事本文テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト<br>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </p>
                    <h3 class="sub-title">サブタイトル</h3>
                    <span>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </span>
                </div>
            </div>
        </article>
    </body>
</html>
@charset "UTF-8";

/* === ベース === */
body {
    font-family: sans-serif;
}

/* === レイアウト === */
.ly-cont {
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

/* === モジュール === */
.bl_module {
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-size: 16px;
    line-height: 1.5;
}

.bl_module .image-wrapper {
    flex: 1 1 25%;
    margin-right: 3.33333%;
}

.bl_module .image-wrapper img {
    width: 100%;
    vertical-align: top;
}

.bl_module .body {
    flex: 1 1 68.33333%;
}

.bl_module .title {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

.bl_module .sub-title {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

.bl_module .body > span {
    color: #555;
    font-size: 14px;
}

だいぶ分かりやすくなってきた。

が、まだ3つ残っているので、どんどん進んでいこう。

クラス名から影響範囲が想像できる

6つ目、Webサイトが大きくなってくると、色々なモジュールが出てくるだろう。

そのため、クラス名もどんどん増えてくる。

その時、そのクラスがどんな範囲に影響するか、というのがぱっと見で分かると嬉しい。

ここでのポイントは、HTML側だけ見た時に予想した影響範囲が、CSSでの設定と一致しているか

今回のサンプルを例に見てみよう。

4つほど気になるクラス名がある。

  • image-wrapper
  • body
  • title
  • sub-title

このあたりは、今回は今作っているモジュールのみに適用されるようCSSで組んでいる。

しかし、このクラス名だけで見ると、他のモジュールで使った場合にも適用できそうな感じがするだろう。

これが、予想した影響範囲と一致していないことになる。

ということでこの解決方法を。

これは、モジュールの子要素には、そのモジュールの元となるクラス名を含ませることで解決する。

今回のモジュール全体には、bl_moduleというクラス名がついている。

そのため、これをそれぞれのクラス名に入れてあげればいい。

例えば、タイトルについてはbl_module_titleとすることで、そのモジュールで使われるタイトルなんだな、ということが分かるようになる。

逆に、他でも使えるようにしたい部分の場合はモジュールのクラス名は入れなければいい

今度はサブタイトル部分、これを他のモジュールでも使いたい場合は、そのまま変えずにsub-titleとしておけばOKだ。

今回は、今見たsub-title部分は他でも使うことを想定、他の3項目はそのモジュール限定を想定して直してみよう。

なお、ここで具体的な設計手法であるPRECSSというものを参考に、ハイフンケースを使用していたクラス名はそれぞれローワーキャメルケースに直しておく

復習で、ハイフンケース各単語をハイフンで繋ぐ形ローワーキャメルケース先頭の単語だけ小文字、2単語目以降は先頭だけ大文字にしてそのまま繋ぐ形だ。

つまり…

  • image-wrapper → bl_module_imageWrapper
  • body → bl_module_body
  • title → bl_module_title
  • sub-title → subTitle

こんなクラス名に変更する。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>第3回CSS設計サンプルページ</title>
        
        <!-- css-wipeのファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/css-wipe.css">

        <!-- 自作CSSファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">
    </head>
    <body>
        <article id="main" class="ly-cont">
            <div class="bl_module">
                <figure class="bl_module_imageWrapper">
                    <img src="./image/sample.jpg" alt="写真:サンプル">
                </figure>
                <div class="bl_module_body">
                    <h2 class="bl_module_title">記事タイトルテキスト</h2>
                    <p>記事本文テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト<br>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </p>
                    <h3 class="subTitle">サブタイトル</h3>
                    <span>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </span>
                </div>
            </div>
        </article>
    </body>
</html>
@charset "UTF-8";

/* === ベース === */
body {
    font-family: sans-serif;
}

/* === レイアウト === */
.ly-cont {
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

/* === モジュール === */
.bl_module {
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-size: 16px;
    line-height: 1.5;
}

.bl_module .bl_module_imageWrapper {
    flex: 1 1 25%;
    margin-right: 3.33333%;
}

.bl_module .bl_module_imageWrapper img {
    width: 100%;
    vertical-align: top;
}

.bl_module .bl_module_body {
    flex: 1 1 68.33333%;
}

.bl_module .bl_module_title {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

/* 順番入れ替え */
.bl_module .bl_module_body > span {
    color: #555;
    font-size: 14px;
}

/* 他でも使うことを想定し、.bl_moduleの子孫セレクタを削除 */
.subTitle {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

さて、6番目に着目したリファクタリングは以上だが、他に直せそうな部分が出てきた。

それぞれのクラスに特定のモジュール内の部品であることを含ませたので、そこを絞る.bl_moduleを親とする子孫セレクターが不要になった。

このため、5番目の内容を使って、それらを消してしまう。

CSSのみの変更なので、その内容だけ記載しよう。

@charset "UTF-8";

/* === ベース === */
body {
    font-family: sans-serif;
}

/* === レイアウト === */
.ly-cont {
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

/* === モジュール === */
.bl_module {
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-size: 16px;
    line-height: 1.5;
}

.bl_module_imageWrapper {
    flex: 1 1 25%;
    margin-right: 3.33333%;
}

.bl_module_imageWrapper img {
    width: 100%;
    vertical-align: top;
}

.bl_module_body {
    flex: 1 1 68.33333%;
}

.bl_module_title {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

.bl_module_body > span {
    color: #555;
    font-size: 14px;
}

.subTitle {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

いい感じになってきた。

クラス名から見た目・機能・役割が想像できる

7番目、一つ上と似ているが、別で用意されているということはやはり異なる部分がある。

例えばだが、クラス名で以下のようなものがついていたらどうだろうか。

  • title1
  • title2
  • title3

…これだと、わけが分からないだろう。

そのため…

  • page-title
  • section-title
  • sub-title

こんな感じにすれば、それぞれどんなタイトルかがクラス名だけで分かるようになる、ということ。

で、今回のサンプルではタイトル部分はすでにこうなっている。

その他に直すとすると…このモジュール自体のクラス名bl_moduleだろう。

他にモジュールが増えた時、添え字で増やしていくわけにもいかない。

そこで、今回作っているような部品は一般的にメディアと呼ばれている部品なので、そこから取ってbl_mediaという名前に変えよう。

例えば、他にカード型やリスト型のモジュールを追加するときは、それぞれbl_cardbl_listのようにすればいい。

ということで、これを直していこう。

もちろん、6つ目でやった親モジュール名の継承部分を変えるのも忘れずに。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>第3回CSS設計サンプルページ</title>
        
        <!-- css-wipeのファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/css-wipe.css">

        <!-- 自作CSSファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">
    </head>
    <body>
        <article id="main" class="ly-cont">
            <div class="bl_media">
                <figure class="bl_media_imageWrapper">
                    <img src="./image/sample.jpg" alt="写真:サンプル">
                </figure>
                <div class="bl_media_body">
                    <h2 class="bl_media_title">記事タイトルテキスト</h2>
                    <p>記事本文テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト<br>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </p>
                    <h3 class="subTitle">サブタイトル</h3>
                    <span>
                        テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
                    </span>
                </div>
            </div>
        </article>
    </body>
</html>
@charset "UTF-8";

/* === ベース === */
body {
    font-family: sans-serif;
}

/* === レイアウト === */
.ly-cont {
    max-width: 1200px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

/* === モジュール === */
.bl_media {
    /* モジュールに対する指定 */
    display: flex;
    align-items: center;
    font-size: 16px;
    line-height: 1.5;
}

.bl_media_imageWrapper {
    flex: 1 1 25%;
    margin-right: 3.33333%;
}

.bl_media_imageWrapper img {
    width: 100%;
    vertical-align: top;
}

.bl_media_body {
    flex: 1 1 68.33333%;
}

.bl_media_title {
    margin-bottom: 10px;
    font-size: 18px;
    font-weight: bold;
}

.bl_media_body > span {
    color: #555;
    font-size: 14px;
}

.subTitle {
    margin-top: 10px;
    margin-bottom: 10px;
    font-size: 16px;
    border-bottom: 1px solid #555;
}

ちなみに、参考書ではなぜ今回mediaというモジュール名にしたかの解説が書かれているが、ちょっと記事がかなりの長さになってきているので、そこは省略しよう。

結論部分だけ引用すると…

結局のところ、使い回しを前提としたモジュールに対する最適な命名とはつまり、
1.コンテキストではなく、見た目・機能・役割をベースとし
2.media・accordion・sliderなど、一般的な呼称を使用した
ものだと筆者は考えています。

CSS設計完全ガイド ~詳細解説+実践的モジュール集

このように書かれていた。

その他、省略した中に書かれているが、こういった名前を考える時は具体的な外部CSSの命名を参考にするのも手だろう。

拡張しやすい

最後のポイントがこれだ。

通常であれば、Webページは公開して終わりではなく、その後メンテナンスの必要性が出てくる。

しかし、その変更を最初から全て見通すことなど不可能で、これをしやすくするために設計しておくのが大事だ。

もちろん、これまで見てきた7項目もこれに繋がってくるし、8個目のこれも当然含まれる。

で、じゃあ拡張しやすいって何なのさという話だが、これには大きく二つの観点がある。

  • クラス設計(マルチクラス設計)を拡張しやすく行う
  • 拡張用で作ったクラスは、適切な粒度や影響範囲を保つ

それぞれの詳細を…といきたいところだが、すでにとんでもない長さになってしまっており、ここでは新たにシングルクラスマルチクラスの解説からしなければならない。

ここだけでも多少長くなりそうなので、次回に切り出して解説することにしよう。

おわりに

今回は、ようやくだがCSS設計の中身に入った。

まずはCSS設計が目指している4つのゴールと、それを達成するための8つのポイントの7つ目までを解説した。

かなりの長さになってしまい、さらに中途半端なところで切れて申し訳ない…が、今回の内容は今後の内容全てにおける下地となる部分だ。

全ていきなり覚えろなんて言うつもりもなく、具体的な設計手法を見ていく中で定着させていってもらえればと思う。

さて、次回はもちろん残ってしまった拡張しやすいというポイントを解説していこう。

その中で、本文中にもちらっと名前を出したシングルクラスマルチクラスという考え方も紹介していく。

次回の内容まで見終えたら、過去に作ったCSSがあればどう直せそうか見直してみるのも面白いだろう。

2021/3/13追記

次回の内容、今回の続きで拡張しやすいという考え方を解説した。

今回の7個はそもそもどうやって書くかの話だったが、8個目は新たな機能を追加することをメインで扱っている。

もちろん、他の7個もこれに繋がってくる話なので、どれかだけ気を付ければいいというものでもないだろう。

今回、次回の内容を併せて認識しておくようにしておきたい。

コメント

タイトルとURLをコピーしました