読み込み中...

HTMLでメニューバーを作成する5つの手順

HTML, メニューバー, CSS, 初心者, 作り方, サンプルコード, カスタマイズ, 注意点 HTML
この記事は約20分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

メニューバーを作成するときは、見た目だけでなく、リンクの意味、キーボード操作、スマートフォンでの折り返しまで同時に考える必要があります。そのため、単に横並びの文字列を置くのではなく、navulliaを組み合わせ、構造と装飾を分けて設計する流れが扱いやすくなります。

これから作成するメニューバーの結論は、navで領域を示し、display:flexで項目を並べ、:hover:focus-visibleで操作中の状態を見せる構成です。ただし、ドロップダウンや固定表示を加える場合は、positionz-indexの影響を受けるため、先に土台を整えるほうが崩れにくくなるのが基本です。

動作確認環境
  • HTML Living Standard
  • CSS Snapshot 2024
  • Google Chrome 126 / Mozilla Firefox 127 / Safari 17
📖 この記事で学べること
  • メニューバー作成に必要な基本構造
  • 横並び、余白、配色を整えるCSSの考え方
  • スマートフォン表示で崩れにくい設計
  • ドロップダウンと固定表示を加える判断基準
  • アクセシビリティと内部リンク設計の確認方法

完成形から逆算してメニューバーを作成する

結論として、標準的なメニューバーは「領域」「リスト」「リンク」「状態表示」の組み合わせで作成します。この構成にしておくと、ページ内移動、カテゴリ一覧、問い合わせ導線などを同じルールで増やせます。

その考え方は、公式仕様の役割分担とも相性がよい形です。要素の意味はWHATWGのnav要素で確認でき、リンクの基本仕様はMDNのa要素が参考になるのが目安です。

<nav class="site-nav" aria-label="主要メニュー">
  <ul class="site-nav__list">
    <li><a href="/web/2387/">アンカーリンク</a></li>
    <li><a href="/web/2517/">スライドショー</a></li>
    <li><a href="/web/2624/">問い合わせ</a></li>
  </ul>
</nav>

.site-nav__list {
  display: flex;
  gap: 16px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-nav a {
  display: block;
  padding: 10px 14px;
  text-decoration: none;
}

.site-nav a:hover,
.site-nav a:focus-visible {
  background: #eef2ff;
  outline: 2px solid #4f46e5;
}

結果: 期待される表示は、3件のリンクが横方向に並び、マウス操作やキーボード操作で背景色と輪郭が変わるメニューバーです。

この最小構成では、aria-labelでナビゲーションの目的を補い、list-style:noneで箇条書き記号を外し、gapで項目間の距離を決めています。ただし、リンク先の数が増えると横幅が足りなくなるため、画面幅に応じた折り返しや縦配置も検討します。

メニューバー作成の早見表

メニューバーの作成では、要素選び、CSS、操作状態、レスポンシブ対応を分けて確認すると抜け漏れが減りますし、ここがポイントです。そのため、作業前に次の早見表で役割を整理しておくと、後からデザインを変える場合も判断しやすくなります。

項目使う要素・プロパティ役割確認する点関連する注意
領域nav主要な移動領域を示す他のリンク群と区別できるかaria-labelを併用する
リストulリンクのまとまりを表す項目の順序が自然か見た目だけで構造を消さない
項目li各リンクを分離する余白が均等か入れ子が深すぎないか
リンクa遷移先を持たせるhrefが正しいか空リンクを避ける
横並びdisplay:flex項目を行方向に配置する狭い幅で崩れないかflex-wrapを検討する
間隔gap項目間の距離を整えるクリックしやすいか余白の重複を避ける
内側余白padding押しやすい面積を作る指で触れやすいか文字だけを狭くしない
外側余白margin周辺要素との距離を保つ見出しと近すぎないか親要素との関係を見る
背景background領域や状態を見せる文字色と差があるか薄すぎる色を避ける
文字色colorリンク文字を読みやすくする背景と対比できるか訪問済み色も考える
下線text-decorationリンクらしさを調整するリンクと分かるか状態表示で補う
輪郭outlineキーボード操作を示す消していないかfocus-visibleを使う
ホバー:hoverマウス操作の反応を出す変化が分かるか色だけに依存しない
フォーカス:focus-visibleキーボード位置を示す十分に目立つかoutline-offsetも使える
現在地aria-current表示中ページを伝える現在地が一目で分かるか複数付けない
固定表示position:stickyスクロール中に残す本文を隠さないかtopを合わせる
重なりz-index前面表示を制御するドロップダウンが隠れないか乱用を避ける
max-width広い画面で読み幅を保つ中央寄せできるかmargin:autoと組む
折り返しflex-wrap狭い幅で行を増やす項目が重ならないか高さの増加を見る
縦配置flex-direction小画面で縦に並べるタップしやすいかメディアクエリと組む
分岐@media画面幅でCSSを切り替える境界幅で崩れないか実際の端末幅を想定する
開閉buttonメニューを開閉する操作対象が分かるかaria-expandedを更新する
状態hidden非表示状態を表す読み上げ対象から外れるかCSSだけの非表示と区別する
装飾border区切り線を加える濃すぎないか背景色と合わせる
角丸border-radiusボタン風の形にするデザインに合うか過度に丸めない
box-shadow浮き上がりを表す文字を邪魔しないか固定表示で控えめにする
速度transition状態変化を滑らかにする遅すぎないか操作反応を妨げない
ドロップダウンposition:absolute子メニューを重ねる親項目から外れないかキーボード操作を確認する
表示制御visibility見え方を切り替えるフォーカス移動と合うかopacityとの違いを見る
サイズfont-size文字の大きさを整える小さすぎないかズーム時も読む

構造はnavとリストで組み立てる

メニューバーの土台では、divだけでリンクを並べるより、navとリストを使う形が自然です。その構造にすると、支援技術や検索エンジンに対して、ページ移動の領域であることを伝えやすくなります。

これにより、内部リンクの設計も整理しやすくなります。たとえばページ内の特定位置へ移動する導線はHTMLでアンカーリンクを活用する方法10選、フォームへの導線はHTMLで問い合わせフォームを作成する方法5選!と結び付けると、読者の移動目的が明確になるのがポイントです。

<nav class="global-menu" aria-label="サイト内メニュー">
  <ul class="global-menu__items">
    <li class="global-menu__item"><a href="/web/2597/">構造</a></li>
    <li class="global-menu__item"><a href="/web/2445/">カレンダー</a></li>
    <li class="global-menu__item"><a href="/web/2517/">表示演出</a></li>
  </ul>
</nav>

結果: 期待される表示は、サイト内メニューという名前を持つナビゲーション領域の中に、構造、カレンダー、表示演出のリンクが並ぶ形です。

このとき、class名は見た目ではなく役割に合わせて付けると保守しやすくなります。ただし、menu1red-linkのように用途が読み取りにくい名前は、後から項目を追加したときに意味がずれやすいので避けます。

💡 Tips: aria-labelは、同じページに複数のnavがあるときに役割を区別する助けになるのが一般的です。主要メニュー、パンくず、フッターリンクなど、同じ要素でも目的が違う場合に使い分けます。

横並びの見た目はflexで整える

構造が決まったら、メニューバーの見た目をCSSで整えます。その中心になるのがdisplay:flexで、リスト項目を横方向に並べながら、gapで距離を管理できるのが現実的です。

一方、古い作り方としてfloatで横並びにする例も残っていますが、現在の作成ではflexgridのほうが配置の意図を読み取りやすいです。公式ドキュメントでも、CSS Flexible Box Layoutとして柔軟な一次元レイアウトが整理されています。

.global-menu {
  background: #ffffff;
  border-bottom: 1px solid #d9dee8;
}

.global-menu__items {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  max-width: 960px;
  margin: 0 auto;
  padding: 12px 16px;
  list-style: none;
}

.global-menu__item a {
  display: block;
  color: #1f2937;
  padding: 10px 12px;
  border-radius: 6px;
  text-decoration: none;
}

結果: 期待される表示は、白い背景の下に薄い境界線が入り、中央寄せされたリンクが一定間隔で横並びになるメニューバーです。

これらの指定では、align-items:centerで縦方向の位置がそろい、justify-content:centerで全体が中央に寄ります。ただし、項目数が多いサイトでは中央寄せより左寄せのほうが探しやすい場合もあるため、情報量に合わせて調整します。

具体的には、メニューの数が少ないブランドサイトなら中央寄せ、カテゴリが多いメディアなら左寄せ、管理画面に近いUIなら余白を抑えた配置が向いていると整理できます。その判断を誤ると、作成したメニューバーが見た目だけ整っていても、目的のリンクを探しにくくなります。

操作中の状態を見える形にする

メニューバーは読むだけの部品ではなく、クリック、タップ、キーボード操作を受ける部品です。そのため、:hoverだけでなく:focus:focus-visibleも合わせて設計する必要があります。

これを省くと、マウスでは問題なく見えても、キーボード操作中に現在位置が分かりにくくなると理解できます。特に押さえたいのは、outline:noneで輪郭を消したまま代替表現を用意しない書き方を避けることです。

.global-menu__item a:hover {
  background: #edf7f2;
  color: #0f5132;
}

.global-menu__item a:focus-visible {
  outline: 3px solid #0f766e;
  outline-offset: 3px;
  background: #ecfeff;
}

.global-menu__item a[aria-current="page"] {
  background: #0f766e;
  color: #ffffff;
}

結果: 期待される表示は、ホバー時に薄い緑系の背景へ変わり、キーボードフォーカス時にはリンクの外側に輪郭が出る状態です。

このとき、現在表示しているページのリンクにはaria-current="page"を付けると、見た目と意味をそろえられます。ただし、複数のリンクに同じ現在地を示す属性を付けると混乱するため、ページ単位でひとつに絞ります。

⚠️ 注意: 色の変化だけで状態を伝えると、見分けにくい利用環境があると覚えるとよいでしょう。背景、輪郭、文字の太さなどを組み合わせ、状態差が視覚的に分かるようにします。

スマートフォン向けに折り返しと縦配置を用意する

横並びのメニューバーは、画面幅が狭くなると文字が詰まりやすくなります。そのため、作成時点でflex-wrapによる折り返し、または@mediaによる縦配置を決めておくと安定すると考えられます。

一般に、項目数が少ない場合は折り返しで十分ですが、項目数が多い場合は開閉式メニューが向いています。ただし、開閉式にするとbuttonaria-expandedhiddenなどの状態管理が増えるため、必要以上に複雑にしない判断も求められます。

.global-menu__items {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

@media (max-width: 640px) {
  .global-menu__items {
    flex-direction: column;
    align-items: stretch;
  }

  .global-menu__item a {
    padding: 12px 14px;
  }
}

結果: 期待される表示は、広い画面では横並び、640px以下の画面ではリンクが縦に積み重なるメニューバーです。

これにより、横幅が足りない状態でもリンク同士が重なりにくくなります。一方、縦配置にした分だけ高さは増えるため、ページ冒頭の見出しや本文を押し下げすぎない余白設計が必要になります。

同様に、スライドショーやカレンダーのような横幅を使う部品が近くにあるページでは、メニューの高さが画面全体の見え方に影響すると言えるでしょう。関連するUIを扱う場合は、HTMLとCSSで手軽に作るスライドショーコピペ12選HTMLとJSを使ってカレンダーを作成・更新する方法10選のような部品との並びも意識します。

ドロップダウンを加えるときの考え方

カテゴリ数が多いサイトでは、メニューバーにドロップダウンを加えたくなる場面があります。その場合でも、親リンクと子リンクの関係をulの入れ子で表し、CSSだけで見た目を無理に作り込まないほうが管理しやすくなるのが基本です。

ただし、ドロップダウンは操作方法が増えるため、初心者がつまずきやすい箇所でもあります。マウスを外した瞬間に消える、キーボードで子項目へ移れない、スマートフォンでタップできないといった問題が起きやすいからです。

<nav class="category-nav" aria-label="カテゴリメニュー">
  <ul class="category-nav__list">
    <li class="category-nav__item category-nav__item--has-child">
      <a href="/web/2597/">学習ガイド</a>
      <ul class="category-nav__child">
        <li><a href="/web/2387/">アンカー</a></li>
        <li><a href="/web/2624/">フォーム</a></li>
      </ul>
    </li>
  </ul>
</nav>

結果: 期待される表示は、学習ガイドの下にアンカーとフォームの子メニューを持つ階層型メニューバーです。

.category-nav__item--has-child {
  position: relative;
}

.category-nav__child {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 180px;
  margin: 0;
  padding: 8px;
  list-style: none;
  background: #ffffff;
  border: 1px solid #d9dee8;
  box-shadow: 0 8px 20px rgb(15 23 42 / 12%);
  visibility: hidden;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .16s ease, transform .16s ease;
}

.category-nav__item--has-child:hover .category-nav__child,
.category-nav__item--has-child:focus-within .category-nav__child {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
}

結果: 期待される表示は、親項目にマウスを重ねるか子リンクへフォーカスしたときに、白い子メニューが下方向へ表示される状態です。

この作り方では、:focus-withinを含めることで、キーボード操作でも子メニューを開きやすくなります。もっとも、スマートフォンではホバーが前提にならないため、必要に応じてJavaScriptで開閉状態を切り替える設計が現実的です。

ℹ️ 補足: ドロップダウンを多用すると、深い階層にあるリンクが見つかりにくくなります。主要カテゴリだけをメニューバーに置き、詳細な一覧はカテゴリページへ誘導する構成も選択肢になるのが目安です。

固定表示にする場合の注意点

スクロール中もメニューバーを残したい場合は、position:stickyを使うと比較的少ないCSSで固定に近い表示を作れます。その表示はページ移動の負担を下げますが、本文の上に重なると読みにくさにつながります。

このとき、topz-index、背景色を合わせて設定するのがポイントです。ただし、管理バーや広告枠など、上部に別の固定要素があるサイトでは、top:0のままだと重なる可能性があります。

.global-menu {
  position: sticky;
  top: 0;
  z-index: 20;
  background: #ffffff;
  border-bottom: 1px solid #d9dee8;
}

結果: 期待される表示は、スクロールしても画面上部に残り、本文より前面に表示されるメニューバーです。

逆に、短いページやランディングページでは、固定表示が読者の視界を狭める場合があります。そのため、固定にするかどうかはデザイン上の好みではなく、移動頻度と画面占有率のバランスで決めますが、これは押さえたい点です。

内部リンクとラベルを整理する

メニューバーの作成では、リンクの見た目より先にラベルの分かりやすさを整える必要があります。その理由は、読者がクリック前に遷移先を判断する材料が、短いラベルと並び順に集中するためです。

具体的には、「詳しく」「こちら」のような曖昧なラベルを避け、リンク先の内容が分かる言葉を使います。ツリー構造の考え方を整理したい場合は、HTMLとツリー構造をマスターする!初心者からプロまでわかる7つの完全ガイドのように、階層とラベルの関係を確認すると理解しやすくなるのが一般的です。

そのうえで、主要カテゴリ、よく読まれるページ、問い合わせ、資料請求などを同じ階層に置きすぎないようにします。一方、運営上どうしても項目が増える場合は、グループ分けやドロップダウンを使い、読者が目的を追いやすい形にします。

💡 Tips: メニューバーのリンクは、ページのすべてを載せる場所ではありません。主要な移動先を絞り、補助的なリンクはフッターやカテゴリページへ回すと、上部の導線が読み取りやすくなるのが現実的です。

作成後に確認したい品質チェック

作成したメニューバーは、見た目が整った段階で終わらせず、操作と意味の両面から確認します。その確認では、リンク切れ、フォーカス表示、スマートフォン幅、現在地表示、外部リンク属性を順に見ると抜けを減らせます。

これらは、公開後の使いやすさに直結すると整理できます。たとえば、target="_blank"を使う外部リンクにはrel="noopener noreferrer"を添え、同一サイト内のリンクでは不要な新規タブを避ける形が一般的です。

ただし、外部リンクと内部リンクの扱いを混ぜると、編集時の判断が曖昧になります。そのため、本文中の公式ドキュメントは新規タブ、サイト内の関連記事は通常遷移というように、作成ルールをそろえておくと運用しやすくなります。

<a href="https://developer.mozilla.org/docs/Web/CSS/:focus-visible" target="_blank" rel="noopener noreferrer">:focus-visibleの解説</a>
<a href="/web/2387/">アンカーリンクの解説</a>

結果: 期待される表示は、外部ドキュメントへのリンクが新しいタブで開き、内部記事へのリンクは同じタブで移動する構成です。

一般に、メニューバーは複数ページで共通利用されるため、小さな不具合がサイト全体へ広がりますし、これが一つの目安です。そのため、テンプレート化する前に、表示幅を変えながらリンクの折り返し、開閉、フォーカス移動を確認します。

実装パターン別の使い分け

メニューバーの作成方法は、サイトの規模によって変わります。小規模なページなら静的な横並びで十分な場合が多く、中規模以上ならレスポンシブ対応やドロップダウン、管理しやすいテンプレート化が必要になると理解できます。

一方、すべての機能を最初から入れると、CSSの依存関係が増えて調整が難しくなります。基本的には、静的な構造、状態表示、スマートフォン対応、必要な場合だけ開閉制御という順序で広げると扱いやすくなります。

パターン向いている場面主な構成気を付ける点
横並び固定項目数が少ないサイトnavflex狭い幅で詰まらないようにする
折り返し型項目数が中程度のサイトflex-wrapgap行数が増えたときの高さを見る
縦配置型スマートフォンを重視するサイト@mediaflex-directionリンク面積を十分に取る
ドロップダウン型カテゴリ階層があるサイトposition:absolute:focus-withinキーボード操作を妨げない
固定表示型長いページが多いサイトposition:stickyz-index本文や上部要素と重ねない

この比較から分かるように、正解はひとつではありません。作成するサイトのページ数、項目数、読者の移動頻度をもとに、最小限の構成から広げる考え方が安定します。

公開前の仕上げ

メニューバーの仕上げでは、構造、装飾、操作、リンク先を同時に確認します。その確認を後回しにすると、見た目だけ完成していても、現在地が分からない、スマートフォンで押しにくい、内部リンクの意図が弱いといった問題が残りやすくなると覚えるとよいでしょう。

そのため、navの役割、aria-labelの有無、hrefの正しさ、:focus-visibleの見え方、@mediaの切り替わりを順に確認します。これらを押さえると、メニューバー作成の品質が見た目だけに偏らず、読者の移動を支える部品として成立します。

とはいえ、最初から複雑な開閉や多階層メニューを作る必要はありません。静的な横並びで目的が足りるなら、その構成を保ち、必要になった段階でドロップダウンや固定表示を加えるほうが保守しやすくなると考えられます。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。