RevComm Tech Blog

コミュニケーションを再発明し 人が人を想う社会を創る

より綺麗な CSS を書くためには

今回は、チーム開発などにおいて運用しやすくなる、エンジニアのための「より綺麗なCSSの書き方」を紹介します。

!important を使わない

例えば、以下のようなHTMLがあったとします。

<style>
p {
  color: red !important;
}
</style>

<p>青色のテキスト</p>
<p>緑色のテキスト</p>

ここで要件として「文字色が赤なのをそれぞれに合った色にしたい」とします。

そこで bluegreen というクラスで色を変更してみます。 修正は以下の通りです。

<style>
p {
  color: red !important;
}
+ .blue {
+   color: blue;
+ }
+ .green {
+   color: green;
+ }
</style>

- <p>青色のテキスト</p>
- <p>緑色のテキスト</p>
+ <p class="blue">青色のテキスト</p>
+ <p class="green">緑色のテキスト</p>

結果は、文字色は変わらず赤色のままです。

これは p タグに対して !important が指定されていることが原因です。

まず、CSS には優先順位があり !important を指定しない場合、後者が優先して適用されます。

  1. p タグ (要素型セレクタ)
  2. .blue または .green (クラスセレクタ)

このような優先順位のことを「詳細度 (Specificity) 」と言います。

参考: 詳細度 - CSS: カスケーディングスタイルシート | MDN

詳細度は 0 以上の数値で計算され、ある要素に対して複数の style が指定される場合、数値(= 詳細度) の高い CSS 定義が優先して適用されます。

しかし !important を使用した場合、詳細度が強制的に上書きされてしまいます。 したがって上記HTMLの例では、

p {
  color: red !important;
}

が優先され、文字色は赤色のままだったのです。

この場合、文字色を変更するには .blue.green の各クラスにも !important を指定するしか方法はありません。 上記で紹介した MDN の参考リンクでも !important の使用は「悪しき習慣」とされています。

また詳細度の計算例をご紹介します。

(Specificity value が高いほど優先順位が高い状態となります)

引用: CSS Specificity - W3Schools

今回のように、影響範囲が目に見える形であればよいですが、そうでない場合は「想定していない箇所まで修正してしまう」ことになります。 基本的に !important は使わない運用にした方が良いでしょう。

仮に運用中のコードで既に !important が使われている場合、なるべく影響範囲が小さくなるような修正にするべきです。

上記例のHTMLで新たに「テキストを太字にしたい」という要件が追加になった場合、以下の修正となるイメージです。

p {
  color: red !important;
  /* こちらに変更を加えると影響範囲が大きい
  font-weight: bold !important; */
}
/* 新たにクラスを用意して適用 */
.text--bold {
  font-weight: bold !important;
}

<p class="text--bold">太字のテキスト</p>

余分な div は書かない

「CSS の書き方とあるのに div ?」と思われるかもしれませんが、とても大切なことです。

1番の大きな理由は、次に話す「CSS セレクタを深くしない」にもつながるのですが「余分なコードを書かずに済む」ためです。

div に限らず、その要素がなくても構成が成り立つ要素を入れると、HTML の構造が複雑になってしまい、開発者・それを解釈してレンダリングするマシンにとっても優しくないコードとなります。 「セマンティクスを意識してコードを書くことで、文書構造をシンプルに保つこと」が CSS をシンプルに保つためにも非常に重要になってきます。

参考: HTML: アクセシビリティの基礎 - ウェブ開発を学ぶ | MDN

例えばよくあるパターンとしては、h2 や p を無意味に囲むものです。

  • Bad:
<div class="wrapper">
  <div class="head_margin">
    <h2 class="head">h2</h2>
  </div>
  <div class="text_margin">
     <p class="text">あいうえお</p>
  </div>
</div>

.wrapper .head_margin .head {
  font-size: 16px;
  margin-bottom: 8px;
}
.wrapper .text_margin .text {
  font-size: 14px;
}

これは、下記のように簡略化することができます。

  • Good:
<div class="wrapper">
  <h2 class="head">h2</h2>
  <p class="text">あいうえお</p>
</div>

.wrapper .head {
  font-size: 16px;
  margin-bottom: 8px;
}
.wrapper .text {
  font-size: 14px;
}

無駄な div (div に限りません) は削減していきましょう。

※ 今回は一例として 不要な div の例を出しましたが、ブロック要素をまとめる場合など例外もあるため、適材適所で使用します。

また「A > B (A の B要素にのみ適用する)」などを使っていると、クラスセレクターを当てるときに、うまく当たらない場合があります。これは下の「余分にセレクタを指定しなくて済む」に繋がってきます。

CSS セレクタを深くしない

CSS セレクタを不用意に深くしてしまうと可読性が下がり、詳細度が上がってしまうため、意図しない修正をしてしまう可能性があります。

例えば「赤」という文字だけ赤色にしたいのに、うまくいかないパターンがでてきます。

例:

.block > .text {
  color: yellow;
  font-size: 12px;
}
.block > .wrapper > .text {
  color: red;
  font-size: 12px;
}
.block > .wrapper > .text > .small {
  font-size: 10px;
}

<div class="block">
  <p class="text">黄色</p>
  <div class="wrapper">
    <p class="text"><span class="small"></span></p>
  </div>
</div>

このように CSS 設計を考慮しない状態でクラスを書くと、深くセレクタを指定することになります。 「文字のサイズは共通化したい」のに共通化ができなくなってしまう、ということになってしまいます。

1ページのみの LP ページなどでは特に困らなくとも、大規模な Webサービス・アプリケーションでやると、管理が大変なことになります。

例えば .block ではなく .block-2 というコンポーネント配下で同じようなことをしたいとき

.block-2 > .text {
  color: yellow;
  font-size: 12px;
}

.block-2 > .wrapper > .text {
  color: red;
  font-size: 12px;
}
.block-2 > .wrapper > .text > .small {
  font-size: 10px;
}

と、同じコードを指定しなければいけません。

同じコードを複数作らずに使いまわすことで共通化ができ、可読性・管理の向上にもつながります。

先ほどのコードを CSS セレクタを深くせずに書くと、以下のような一例になります。

<style>
.block .text {
  font-size: 12px;
}
.block .text--yellow {
  color: yellow;
}
.block .text--red {
  color: red;
}
.text > .small {
  font-size: 10px;
}
</style>

<div class="block">
  <p class="text--yellow">黄色</p>
  <div class="wrapper">
    <p class="text--red"><span class="small"></span></p>
  </div>
</div>

一見すると最初のコードより量が増えたように見えますが、.block 配下の .text に font-size を一括で指定することができています。

このように「階層構造が違うだけで、スタイル自体の指定は同じコード」はコード管理のコストが減るため、できるだけ共通化した方がよいです。

その他の解決策としては「ユニークなクラス名を使用する」などがあります。 (例: .block > .text.block > .wrapper > .text も、クラスの役割は同一のため)

HTML に style を直接指定しない

<div style="background: blue"> のように、直接 HTML 要素に CSS を記載しているケースがあります。

このように、HTML に直接 style 要素を記述するのは避けましょう。(インラインスタイルとも呼ばれます)

インラインスタイルを使用すると外部 CSS よりも優先されるため見通しが悪くなり、コードの保守性の低下につながります。

  • Bad:
// HTML
<button style="background: blue;">ボタン</button>
  • Good:
// CSS
.bg-blue {
  background: blue;
}

// HTML
<button class="sample-button">ボタン</button>

自分より外のコンポーネントに margin の情報を持たせない

このデザインを作りたいとき、あなたならどうコーディングしますか? よく下記のようなコードが書かれがちですが、実はベストプラクティスではありません。

<style>
.title {
  margin-top: 16px;
}
.title_text {
  margin-top: 16px;
  margin-bottom: 16px;
}
</style>

<div class="wrapper">
  <h2 class="title">title</h2>
  <p class="title_text">sub title</p>
</div>

このように「自分より親の要素」に対して余白を空けたいときに情報を持たせるべきではありません。(この場合は .wrapper の上余白調整のためのCSS)

  • .title を他の要素で使いたくなったときに、その要素用に CSS を書き直さなくてはいけなくなる
  • .title の上に何か要素を置いたときに .title で保っていた上部分の余白を、新規で置いた要素に置き換えなければいけなくなる

などのデメリットが出てきます。

この場合は .title に情報を持たせるのではなく .wrapper に余白の情報を持たせるべきです。

<style>
.wrapper {
  padding: 16px;
}
.title_text {
  margin-top: 16px;
}
</style>

<div class="wrapper">
  <h2 class="title">title</h2>
  <p class="title_text">sub title</p>
</div>

まとめ

以上、より綺麗な CSS を書くためのワンポイントアドバイスを紹介しました。

アドバイスとありますが、今回記載したものはあくまで実践で得た一例になります。 開発をする上での 一つの指標にしていただければと思います。

参考リンク: MDN による CSS のまとめ: https://developer.mozilla.org/ja/docs/Web/CSS