WordPressのグローバルナビは、管理画面から項目を編集できる便利さがある一方、テーマ側の出力をそのまま使うだけでは「よくある普通のメニュー」になりがちです。
この記事では、メニューの登録からHTML出力、2026年らしい配色、ホバー・現在地表示、モバイルメニューまでを一つの実装としてまとめます。プラグインに頼らず、自作テーマへ組み込める方法です。
完成イメージと設計方針
- PCでは横並びで、現在ページをアクセントカラーで表示
- ホバーとキーボードフォーカスの両方で状態が分かる
- スマートフォンではメニューボタンで開閉
- 管理画面の「メニュー」から項目や順番を変更できる
- JavaScriptが動かない場合も主要リンクへ到達できる
見た目を整える前に、WordPressの標準APIで編集可能なメニュー領域を作ります。
1. functions.phpでメニューを登録する
register_nav_menus()をafter_setup_themeで実行し、テーマが利用するメニュー位置を登録します。
function nines_register_menus() {
register_nav_menus([
'global' => 'グローバルナビゲーション',
'footer' => 'フッターナビゲーション',
]);
}
add_action('after_setup_theme', 'nines_register_menus');
登録後、WordPress管理画面の「外観」からメニューを作成し、「グローバルナビゲーション」の位置へ割り当てます。ブロックテーマではナビゲーションブロックを使う構成もありますが、ここではクラシックテーマを前提にしています。
2. header.phpでwp_nav_menu()を出力する
wp_nav_menu()へテーマ位置、コンテナ、クラスを指定します。fallback_cbをfalseにすると、メニュー未設定時に意図しないページ一覧が出力されません。
<header class="site-header">
<a class="site-logo" href="<?php echo esc_url(home_url('/')); ?>">
<?php bloginfo('name'); ?>
</a>
<button
class="nav-toggle"
type="button"
aria-expanded="false"
aria-controls="global-navigation"
>
<span class="nav-toggle-label">MENU</span>
</button>
<nav id="global-navigation" class="global-nav" aria-label="グローバルナビゲーション">
<?php
wp_nav_menu([
'theme_location' => 'global',
'container' => false,
'menu_class' => 'global-nav-list',
'fallback_cb' => false,
'depth' => 2,
]);
?>
</nav>
</header>
開閉ボタンはbutton要素を使い、対象ナビのIDをaria-controlsで示します。aria-expandedはJavaScriptで実際の開閉状態と同期します。
3. CSSでモダンな横並びナビを作る
白背景、黒い文字、鮮やかなアクセントをベースにすると、記事サイトでも読みやすく軽快な印象になります。色だけに頼らず、下線とフォーカスリングも使います。
:root {
--nav-text: #111;
--nav-bg: #fff;
--nav-accent: #ff2f63;
--nav-focus: #2384ff;
--nav-border: #d8d8d8;
}
.site-header {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
gap: 32px;
min-height: 80px;
padding-inline: clamp(20px, 4vw, 64px);
border-bottom: 1px solid var(--nav-border);
background: var(--nav-bg);
}
.global-nav-list {
display: flex;
align-items: center;
gap: clamp(20px, 3vw, 44px);
margin: 0;
padding: 0;
list-style: none;
}
.global-nav-list a {
position: relative;
display: block;
padding-block: 28px;
color: var(--nav-text);
font-weight: 700;
text-decoration: none;
}
.global-nav-list a::after {
content: "";
position: absolute;
inset-inline: 0;
inset-block-end: 18px;
block-size: 3px;
background: var(--nav-accent);
transform: scaleX(0);
transform-origin: right;
transition: transform .2s ease;
}
.global-nav-list a:hover::after,
.global-nav-list a:focus-visible::after,
.global-nav-list .current-menu-item > a::after,
.global-nav-list .current-menu-ancestor > a::after {
transform: scaleX(1);
transform-origin: left;
}
.global-nav-list a:focus-visible {
outline: 3px solid var(--nav-focus);
outline-offset: 4px;
}
WordPressは現在のメニュー項目へcurrent-menu-item、親項目へcurrent-menu-ancestorなどのクラスを付けます。PHPでURLを比較せず、この標準クラスを利用できます。
4. モバイルメニューを実装する
モバイルでは横幅が足りないため、ナビを画面幅いっぱいのパネルとして開閉します。デスクトップではボタンを非表示にします。
.nav-toggle {
display: none;
}
@media (max-width: 767px) {
.nav-toggle {
display: inline-grid;
place-items: center;
min-width: 48px;
min-height: 48px;
border: 2px solid #111;
background: #111;
color: #fff;
}
.global-nav {
position: absolute;
z-index: 20;
inset-inline: 0;
inset-block-start: 100%;
visibility: hidden;
opacity: 0;
transform: translateY(-8px);
border-bottom: 1px solid var(--nav-border);
background: #fff;
transition: opacity .2s, transform .2s, visibility .2s;
}
.global-nav.is-open {
visibility: visible;
opacity: 1;
transform: translateY(0);
}
.global-nav-list {
display: grid;
gap: 0;
padding: 12px 20px 24px;
}
.global-nav-list a {
padding: 18px 4px;
border-bottom: 1px solid var(--nav-border);
}
}
5. JavaScriptで開閉状態を同期する
const toggle = document.querySelector('.nav-toggle');
const navigation = document.querySelector('#global-navigation');
if (toggle && navigation) {
toggle.addEventListener('click', () => {
const isOpen = toggle.getAttribute('aria-expanded') === 'true';
toggle.setAttribute('aria-expanded', String(!isOpen));
navigation.classList.toggle('is-open', !isOpen);
});
navigation.addEventListener('keydown', (event) => {
if (event.key !== 'Escape') return;
toggle.setAttribute('aria-expanded', 'false');
navigation.classList.remove('is-open');
toggle.focus();
});
}
開閉するたびにaria-expandedを更新します。Escapeキーで閉じ、フォーカスをメニューボタンへ戻すとキーボード利用者にも操作しやすくなります。
6. ドロップダウンメニューを整える
第2階層を使う場合、.sub-menuを基準に表示を制御します。PCのホバーだけでなく、:focus-withinでも開くようにします。
.menu-item-has-children {
position: relative;
}
.sub-menu {
position: absolute;
z-index: 30;
inset-block-start: calc(100% - 12px);
inset-inline-start: 0;
min-width: 220px;
margin: 0;
padding: 8px;
visibility: hidden;
opacity: 0;
transform: translateY(8px);
border: 1px solid var(--nav-border);
background: #fff;
box-shadow: 0 16px 40px rgb(17 17 17 / .12);
list-style: none;
transition: opacity .2s, transform .2s, visibility .2s;
}
.menu-item-has-children:hover > .sub-menu,
.menu-item-has-children:focus-within > .sub-menu {
visibility: visible;
opacity: 1;
transform: translateY(0);
}
.sub-menu a {
padding: 12px 14px;
}
スマートフォンで階層メニューを多用すると操作が複雑になります。主要ページが5〜6件なら、全項目を最初から縦に表示する方が迷いにくい場合もあります。
よくある失敗
- メニュー項目をheader.phpへ直書きし、管理画面から変更できない
- ホバー時だけ色を変え、キーボードフォーカスを用意しない
- 通常時の文字色と背景色のコントラストが低い
- モバイルメニューを開いても
aria-expandedがfalseのまま - 現在ページの標準クラスを使わず、URL文字列を独自比較する
- 長い英単語やメニュー数増加時の折返しを確認しない
- ヘッダーをfixedにして本文の上へ重ねてしまう
仕上げのチェックリスト
- 管理画面から項目と順番を変更できる
- マウス、タッチ、Tabキーのすべてで操作できる
- 現在ページが色以外でも判別できる
- 360px前後の画面幅でも文字が切れない
- メニュー開閉時にレイアウトが不自然にずれない
- JavaScriptエラーがなく、Escapeキーで閉じられる
まとめ
WordPressのグローバルナビをおしゃれにするコツは、装飾を増やすことではなく、標準APIで編集可能にし、通常・ホバー・フォーカス・現在地・モバイルの状態を一貫して設計することです。
まずはregister_nav_menus()とwp_nav_menu()で土台を作り、アクセント下線、十分なコントラスト、明確なフォーカス表示を加えてください。それだけでも、テーマらしさと操作性を両立したナビになります。