CSSの治安を取り戻す – 最初の30分

Gaji-Labo では稼働中のウェブサービスやウェブアプリケーションの CSS の改善するお仕事をいただくことがちょいちょいあります。
その際「CSSのリファクタリングなんて請けてくれる会社聞いたことない」というような趣旨のお話をぽろっといただきます。(実際にはほかにもやってる会社さん沢山あると思いますが、たしかにあまり聞かないですね)

今回は初めて入るプロジェクトで CSS の改善をする際、最初に CSS のどこを見るかまとめてみました。
CSS の得意な方が参加していないチーム向けの軽い内容です。ここに上げているような箇所に思い当たりがある場合、少しずつ CSS の実装にストレスを感じはじめているかもしれません。

真っ先に見極めること

プロジェクトに参加して CSS が見られるようになり、手元の開発環境も無事整ったとき、僕が最初に気にする点です。
CSS はこうなってると大変というポイントは沢山ありますが、まずは下記のような問題を抱えていないか簡易チェックを行います。

  • reset.css, normalize.css, base.css (相当のCSS)以外でタイプセレクター(h1 とか div とか span とか要素に直接スタイルを)を多用しているか
  • class 名が単純かつ重複しているか
  • スタイルの上書き(カスケーディング)が沢山されているか
  • utility class 的なものが多用されているか

ちなみにここであげている4点は改修がかなり大掛かりになる可能性のあるものです。これらが問題なければ安全かというとそうではない場合が多いことにご留意ください。

他にも z-index がバラバラで重なりあわせ(Stacking context)が意図通りにならないとか、無秩序な overflow: hidden が原因で思うようにコンポーネント追加ができないなどありますが、これらは修正箇所がある程度絞り込めるので今回は記述を外しました。

タイプセレクターの多用

タイプセレクターを多用していると後から必要になったスタイルのために要素に指定されたスタイルを打ち消すような指定が頻出するようになります。
分かりやすく極端な例を提示します。
※. からはじまるような注記へのページ内リンクを想定したコンポーネントを作成したとします。

<a href="#" class="NoticeLink"><span>※.</span>リンク先</a>

.NoticeLink { text-decoration: underline; position: relative; }
.NoticeLink span { /* ※. のポジション指定を想定したコード */ }

↓このコンポーネントに外部リンクを設定し、外部リンクを表すアイコンを表示する要件が後から発生してしまった場合、下記のような上書きをすることになります。
(実際には ※. の部分を ::after など疑似要素を利用したりすることで回避可能ですが、わかりやすい例として提示しています。)

<a href="https://example.com/" target="_blank" class="NoticeLink"><span>※.</span>リンク先<span class="external">別ウィンドウでリンクを開きます</span></a>

.NoticeLink { text-decoration: underline; position: relative; }
.NoticeLink span { /* ※. のポジション指定を想定したコード */ }
.NoticeLink .external { /* ※. のポジション指定を打ち消したうえで外部リンクアイコンを表示 */}

このコードには下記の問題があります。

  • .external に素直にアイコンのスタイルを指定できない
  • ※. 部分のスタイルを変更するたびに見た目上関係がないように見える .external に影響が及ぶ
  • CSSのソースコード上 span のスタイルが .external に影響することが分からない
    • HTMLと組み合わせたり実際の画面を確認しなければ問題に気づけない
    • 作業している画面やHTMLに問題が再現するパターンが存在しているとは限らない(.external アイコンが使われる箇所がサイト内に1箇所しかなければそれを確認する可能性はとても低い)

タイプセレクターはサイトやアプリケーションを運用していくうえで大きな障壁となる事が多いので極力指定をさけるべきです。
とくに divspan のようなどこにでも出現する可能性がある要素で指定するのはとても危険です。

class 名が単純

シンプルな構成ページなどを実装する場合に .title や .detail などの Class 名をつけたくなると思いますが、単純な class 名を使用していると思わぬコンポーネントの組合せで事故がおきます。

下記のような別々に使う想定で作成されたコンポーネントがあるとします。

<div class="FooColumn">
  <h2 class="title">本来見出し一個に段落ひとつを想定していたコラムコンポーネント</h2>
  <p>本文本文本文本文</p>
</div>

<div class="FooHeading03">
  <h3 class="title">汎用の見出し</h3>
  <p class="detail">見出しとセットで補足文章が必要なので親 div.FooHeading03 からがコンポーネント</p>
</div>

.FooColumn .title  {}
.FooHeading03 .title {}
.FooHeading03 .detail {}

それらのコンポーネントがなんらかの理由で組み合わさったとき、意図せぬ継承が起こります。

<div class="FooColumn">
  <h2 class="title">コラムの見出し</h2>
  <p>本文本文本文本文</p>
  <div class="FooHeading03">
    <h3 class="title">突然の汎用h3</h3> <!-- ←ここに .FooColumn .title が継承されてしまう -->
      <p class="detail">本文本文本文本文</p>
  </div>
  <p>本文本文本文本文</p>
</div>

.FooColumn や .FooHeading03 などの指定で名前空間が切り分けられていると思っても、意図せぬ運用によって容易に破綻するのが CSS のカスケーディングの怖さです。

.title, .detail, .option などなどつい使いたくなりますが、一意性の低い命名は避けるべきです。

※ Shadow DOM や Vue, React などモダンな技術によって Scoped CSS の概念が一般化してきているため class 名の一意性の低さがあまり問題にならなくってきていますが、コード検索のしやすさを考えるとやはり class 名は一意性を高めるべきと考えています。このあたりは次回以降でまとめます。

スタイルの上書きが多用されている

CSS(Cascading Style Sheets)はカスケード(上書き)できる事が最大の特徴と言えると思いますが、この特徴こそが CSS の管理を難しくしているのではないでしょうか。
ブラウザの DevTools で要素のスタイルを確認したとき、あまりにも大量のセレクターによってスタイルが多段にあてられていたり、同じプロパティが何度も上書きされているとすれば CSS を1行追加するにもストレスを感じるようになっている可能性があります。

目の前の要素やコンポーネントのスタイルを修正するときに様々な css ファイルを参照しなければいけないとしたら、一箇所を修正することで影響が広範にわたることを示しています。
ほんの少しの見落としや考慮漏れでスタイルが大きく崩れる可能性があります。

utility class 的なものが多用されている

マージン指定やフォントサイズ指定、カラムの横幅指定などサイト全体で共通化させることで見た目を統一させたいときに、それらを指定するためだけの Utility class ( 便利クラスと呼んだり呼び名は様々かもしれません)のようなものを用意することがあります。

これらも過剰に使い始めるとメンテナンスの難しいコードになっていく場合があります。

慎ましい使い方

個人的には Utility class は使用しないに越したことはないと考えていますが、下記のようなコンポーネント間の微調整に使う用途であれば問題ない場合も多いと思います。
(とはいえ、コンポーネント単位で余白設計が成立している方がコード上はより好ましいです)

<h2 class="FooHeading">なにかの表</h2>
<table class="FooTable mt60 mb30"> <!-- 見出しとの marign はあけて、注記との marign は狭めたい -->
</table>
<p class="FooNotice mt0">※. 表にたいする注記</p>

.mt0 { margin-top: 0; }
...
.mt60 { margin-top: 60px; }
...
.mb30 { margin-bottom: 60px; }

過剰な例

しかし、下記のようにあらゆる調整を Utility class で賄うようになると問題は深刻化します。

<h2 class="FooHeading fs16">なにかの表</h2>
<table class="FooTable mt60 mb30 fs14"> <!-- 見出しとの marign はあけて、注記との marign は狭めたい -->
</table>
<p class="FooNotice mt0 fs12">※. 表にたいする注記</p>

.fs12 { font-size: 12px; }
.fs14 { font-size: 14px; }
.fs16 { font-size: 16px; }

これらは本来見出しやテーブルなどが持っているべきフォントサイズ指定を Utility class でまかなっているパターンです。
極端な例に思えるかもしれませんが、 Utility class を整備しすぎるとまずは Utility class を指定したうえで足りないスタイルのみをコンポーネント側で定義するという運用がなされる場合がまれにあります。

Utility class はコンポーネントの設計で担保しきれない場合(コンポーネントの組合せによって無限にパターンが生まれてしまう余白設計など)のみの使用にとどめるなど極力頼らないで済む方向でガイドラインを作成するのがよいでしょう。

簡易チェックがおわったら

初期の段階ではこれらのチェックを詳細には行わず、全体把握をするために css ファイルをバーっと眺めたり特徴的なページをブラウザで表示しながら DevTools で実際のスタイルの当たり方を見ていきます。
ざっくりと傾向がつかめれば十分です。

その上でサイト全体に深刻な問題があるか、ある程度部分改修で軌道修正できるのかなどを判断し改修の進め方を検討します。
なお、ここで上げた4つの点のどれかがアプリケーション全体に及んでいる場合、改修は地道かつ修正中の不具合がある程度予想される大変な道のりになることが予想されます。(CSS in JS などにより問題が抑制されている場合もありますが、運用でストレスを感じていなければ今は問題ないかもしれません。)

次回以降は普段どんな方針で改修を進めていくかなどをまとめていけたらなと思っています。

宣伝

どこに相談したり発注したりしたらいいか分からない CSS のお悩みなどお答えしています。
「全体改修となると大掛かりだけど部分改修だけでも進めたい」「最初の方だけ段取りとやり方を見せてもらって途中から内部で作業を進めるようにしたい」「フレームワークが〇〇だから外注先が少なくて」などにもご相談に応じます。

要求や要件の定義ができなくて発注の仕方に困っている場合も対応可能です。初回のヒアリングは無料で対応しているのでぜひお問い合わせください。

フロントエンドの悩み、お気軽にご相談ください!

Gaji-Laboはフロントエンド体制や開発効率の問題点や隠れた課題を洗い出し、最適な方法での解決を提案します。フロントエンドの悩みを紐解きながらチーム全体の生産性をアップさせるための相談相手として、お気軽にお声がけください。

オンラインでのヒアリングやミーティングにも対応しておりますので、リモートワーク対応可のパートナーをお探しの場合も是非弊社にお問い合わせください!

お問い合わせしてみる!


投稿者 原田 直貴

受託と事業会社の両方を経験し、沢山の事業を見てみたい気持ちで Gaji-Labo を共同創業。普段は雑用やったりプロジェクトマネジメントやったり、たまにフロントエンドのコードを書いたり。直近は Gaji-Labo をデザイン会社に転換していく課題に挑戦中。期待値コントロールにステ全振り。