👌

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

に公開

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

〇課題 ドロップダウンナビゲーション
一見すると機能しますが、HTMLがdivタグばかりで構造がわかりにくく、CSSも特定階層に依存した長いセレクタが多用されています。後からメニュー項目を増やしたり、デザインを変更したりするのが困難な状態です。

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

<div class="top-nav">
  <div class="nav-container">
    <div class="menu-item"><a href="/">ホーム</a></div>
    <div class="menu-item has-sub">
      <a href="#">サービス</a>
      <div class="sub-menu">
        <div class="sub-item"><a href="/s1">Web制作</a></div>
        <div class="sub-item"><a href="/s2">アプリ開発</a></div>
        <div class="sub-item"><a href="/s3">保守運用</a></div>
      </div>
    </div>
    <div class="menu-item"><a href="/news">お知らせ</a></div>
    <div class="menu-item"><a href="/contact">お問い合わせ</a></div>
  </div>
</div>
.top-nav {
  background: #333;
  height: 60px;
}

.nav-container {
  display: flex;
  margin: 0 auto;
  max-width: 1000px;
}

.menu-item {
  position: relative;
  line-height: 60px;
  padding: 0 20px;
}

.menu-item a {
  color: white;
  text-decoration: none;
}

/* 複雑なネストと特定の構造への依存 */
.menu-item.has-sub:hover .sub-menu {
  display: block;
}

.sub-menu {
  display: none;
  position: absolute;
  top: 60px; /* 固定値(マジックナンバー) */
  left: 0;
  background: #444;
  width: 200px;
  line-height: 40px;
}

.sub-item {
  padding: 0 15px;
  border-bottom: 1px solid #555;
}

.sub-item:hover {
  background: #555;
}

〇リファクタリングの指針
名著『リーダブルコード』に基づき、以下の点を意識しました。
無関係な下位問題を抽出する
メインのナビゲーションという大きな問題から、ドロップダウンという「独立した部品」を切り離します。これにより、ドロップダウン単体での再利用性が高まります。

一度に一つのことを
レイアウトの配置、項目の装飾、ホバー時の動作といったタスクを分離し、単純なルールの組み合わせで実装します。

セマンティックなHTML
divの羅列を卒業し、ナビゲーションにはnav、リストにはul/liなど、機械にも意味が伝わるタグを選定します。

〇修正後コード

<nav class="global-nav" aria-label="メインナビゲーション">
  <ul class="nav-list">
    <li class="nav-item">
      <a href="/" class="nav-link">ホーム</a>
    </li>
    
    <li class="nav-item has-dropdown">
      <a href="#" class="nav-link" aria-haspopup="true" aria-expanded="false">サービス</a>
      <ul class="dropdown-menu">
        <li class="dropdown-item"><a href="/s1">Web制作</a></li>
        <li class="dropdown-item"><a href="/s2">アプリ開発</a></li>
        <li class="dropdown-item"><a href="/s3">保守運用</a></li>
      </ul>
    </li>
    
    <li class="nav-item">
      <a href="/news" class="nav-link">お知らせ</a>
    </li>
    
    <li class="nav-item">
      <a href="/contact" class="nav-link">お問い合わせ</a>
    </li>
  </ul>
</nav>
:root {
  /* 変数による意図の明確化(Chapter 2) */
  --nav-height: 60px;
  --nav-bg-color: #333;
  --dropdown-bg-color: #444;
  --text-color: #fff;
  --accent-color: #555;
  --nav-max-width: 1000px;
}

/* 1. レイアウトのタスク(一度に一つのことを) */
.global-nav {
  background-color: var(--nav-bg-color);
  height: var(--nav-height);
}

.nav-list {
  display: flex;
  margin: 0 auto;
  padding: 0;
  max-width: var(--nav-max-width);
  list-style: none;
  height: 100%;
}

/* 2. ナビゲーション項目の装飾 */
.nav-item {
  position: relative;
  height: 100%;
}

.nav-link {
  display: flex;
  align-items: center;
  padding: 0 20px;
  height: 100%;
  color: var(--text-color);
  text-decoration: none;
}

/* 3. 下位問題:ドロップダウンの振る舞い */
.dropdown-menu {
  display: none;
  position: absolute;
  top: var(--nav-height); /* 変数を利用してマジックナンバーを排除 */
  left: 0;
  min-width: 200px;
  margin: 0;
  padding: 0;
  list-style: none;
  background-color: var(--dropdown-bg-color);
  box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}

.nav-item:hover .dropdown-menu {
  display: block;
}

.dropdown-item a {
  display: block;
  padding: 12px 16px;
  color: var(--text-color);
  text-decoration: none;
  border-bottom: 1px solid var(--accent-color);
}

.dropdown-item a:hover {
  background-color: var(--accent-color);
}

〇主な修正ポイント
セマンティックなマークアップへの転換
nav、ul、liタグを採用。検索エンジンやスクリーンリーダーに構造を正しく伝えます。さらにaria属性を加え、アクセシビリティにも配慮しました。

無関係な下位問題の抽出
dropdown-menuという独立したクラスを作ることで、メインのナビゲーションを汚さずにメニュー専用のスタイルを定義しました。

一度に一つのことを
配置(Flexbox)、装飾(Color)、動作(Hover)をルールごとに整理。どこを直せば何が変わるかを予測しやすくしました。

マジックナンバーの排除と変数化 top: 60pxといった数値を--nav-heightという変数に置き換えました。ヘッダーの高さを変えても、1箇所の修正ですべてが連動する保守性を確保しています。

〇参照先
▼公式ドキュメント
https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Elements/nav

https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Elements/ul

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

以上

Discussion