😺

【13日目】『リーダブルコード』を意識してHTML/CSSをリファクタリングしてみた

に公開

技術ブログ13日目。
本日は、HTML/CSSの読みやすさを追求します。

〇課題
複雑な「料金プラン表」
一見正しく表示されますが、特定の要素を強調するためにセレクタが複雑化しており、後からのデザイン変更やプラン追加が困難な密結合なコードを改善します。

〇修正前コード(動くけれど読みにくいコード)

<section class="pricing">
  <div class="main-container">
    <div class="plan-box">
      <h3>基本プラン</h3>
      <p class="price">¥980</p>
      <button>申し込む</button>
    </div>

    <div class="plan-box active">
      <div class="badge">人気</div>
      <h3>プロプラン</h3>
      <p class="price">¥2,980</p>
      <button>申し込む</button>
    </div>

    <div class="plan-box">
      <h3>ビジネスプラン</h3>
      <p class="price">¥9,800</p>
      <button>申し込む</button>
    </div>
  </div>
</section>
/* 巨大な式(長いセレクタ)と複雑な制御フロー */
section.pricing div.main-container div.plan-box {
  width: 300px;
  padding: 20px;
  border: 1px solid #ccc;
  float: left; /* 古い手法 */
  margin: 10px;
}

/* 読み手の脳に負担をかける複雑な条件指定 */
section.pricing div.main-container div.plan-box.active {
  border: 2px solid #ff4500;
  transform: scale(1.1);
  background-color: #fffaf0;
}

/* 深すぎるネストのような指定 */
section.pricing div.main-container div.plan-box.active h3 {
  color: #ff4500;
  font-size: 24px;
}

/* マジックナンバー(説明のない数値) */
section.pricing div.main-container div.plan-box.active p.price {
  margin-top: 15px;
  font-weight: 900;
  color: #333;
}

/* 状態によって打ち消し合うコード */
section.pricing div.main-container div.plan-box button {
  background-color: #eee;
  border: none;
  padding: 10px 20px;
}

section.pricing div.main-container div.plan-box.active button {
  background-color: #ff4500;
  color: white;
}

〇リファクタリングの指針
名著『リーダブルコード』に基づき、以下の点を意識しました。
巨大な式を分割する
長いセレクタはHTML構造への依存が強く修正に弱いため、クラス名1つで指定できるように簡略化する。

制御フローを読みやすくする
詳細度(セレクタの強さ)の競合を避け、スタイルの上書きが予測通りに動くように設計する。

説明用変数(CSS変数)の導入
具体的な数値や色に名前をつけることで、デザインの意図をコードに反映させる。

〇修正後コード

<section class="pricing">
  <div class="pricing__grid">
    <article class="plan-card">
      <h3 class="plan-card__title">基本プラン</h3>
      <p class="plan-card__price">¥980</p>
      <button class="plan-card__button">申し込む</button>
    </article>

    <article class="plan-card plan-card--active">
      <span class="plan-card__badge">人気</span>
      <h3 class="plan-card__title">プロプラン</h3>
      <p class="plan-card__price">¥2,980</p>
      <button class="plan-card__button">申し込む</button>
    </article>

    <article class="plan-card">
      <h3 class="plan-card__title">ビジネスプラン</h3>
      <p class="plan-card__price">¥9,800</p>
      <button class="plan-card__button">申し込む</button>
    </article>
  </div>
</section>
:root {
  /* 変数に情報を詰め込む*/
  --color-primary: #ff4500;
  --color-border: #ccc;
  --color-bg-light: #fffaf0;
  --color-text-main: #333;
  --spacing-base: 20px;
}

/* レイアウト:Flexboxで制御フローを単純化*/
.pricing__grid {
  display: flex;
  justify-content: center;
  gap: 24px;
  padding: 40px;
  flex-wrap: wrap;
}

/* 基本コンポーネント:式を分割して簡潔なセレクタに */
.plan-card {
  flex: 1;
  min-width: 280px;
  max-width: 320px;
  padding: var(--spacing-base);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  text-align: center;
  transition: all 0.3s ease;
}

.plan-card__title {
  font-size: 1.25rem;
  margin-bottom: 16px;
}

.plan-card__price {
  font-size: 2rem;
  font-weight: 900;
  margin-bottom: 24px;
}

.plan-card__button {
  width: 100%;
  padding: 12px;
  border: none;
  background-color: #eee;
  cursor: pointer;
}

/* 状態の変化:差分だけを記述する(制御フローの最適化) */
.plan-card--active {
  border: 2px solid var(--color-primary);
  background-color: var(--color-bg-light);
  transform: scale(1.05);
  position: relative;
}

.plan-card--active .plan-card__title {
  color: var(--color-primary);
}

.plan-card--active .plan-card__button {
  background-color: var(--color-primary);
  color: white;
}

.plan-card__badge {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--color-primary);
  color: white;
  padding: 4px 12px;
  border-radius: 20px;
  font-size: 0.8rem;
}

〇主な修正ポイント
セレクタの簡略化:
長いセレクタを廃止。
クラス名1つに集約することで、HTMLの階層変更に左右されない「疎結合」なコードにしました。

詳細度のフラット化:
タグ名をセレクタに含めず、全てクラスベースに統一。予期せぬスタイルの競合を防いでいます。

CSS変数の導入:
色や余白を変数化し、プロジェクト全体で一貫性を保てるようにしました。

モダンなレイアウト:
float を flexbox に置き換え、要素間の間隔(gap)を直感的に制御できるようにしました。

〇参照先
▼公式ドキュメント
https://developer.mozilla.org/ja/docs/Web/CSS/Guides/Cascade/Specificity

https://developer.mozilla.org/ja/docs/Web/CSS/Guides/Cascading_variables/Using_custom_properties

https://developer.mozilla.org/ja/docs/Learn_web_development/Core/CSS_layout/Flexbox

▼書籍
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック

以上

Discussion