この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:3
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: ナビゲーションの現在ページをハイライトする方法
SEOタイトル: Vue.js でナビゲーションの現在ページをハイライトする方法

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li>Vue Router 利用時は <strong><code><router-link></code></strong> が自動付与する <code>router-link-active</code> / <code>router-link-exact-active</code> CSS クラスを利用</li><li><strong>カスタムクラス名</strong>は <code>createRouter</code> の <code>linkActiveClass</code> / <code>linkExactActiveClass</code> オプション</li><li>個別 <code><router-link></code> に <code>active-class="..."</code> を渡せばその要素だけ別クラス</li><li><code>computed</code> + <code>$route.path</code> で <code>:class</code> バインドする手法も汎用的</li><li>Nuxt 3 は <code><NuxtLink></code> が同じ動作。<code>router-link-active</code> がそのまま使える</li></ul></td></tr></table>
<h2>Vue Router のデフォルト挙動</h2>

<p>Vue Router を使ったプロジェクトでは <code><router-link></code> が現在ルートにマッチした要素に自動でクラスを付与します:</p>

<ul>
<li><strong><code>router-link-active</code></strong> — そのリンク先 (またはサブパス) にいる場合</li>
<li><strong><code>router-link-exact-active</code></strong> — そのリンク先と<strong>完全一致</strong>している場合</li>
</ul>

<h2>最小構成</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-vue"><!-- App.vue -->
<template>
  <nav>
    <router-link to="/">トップ</router-link>
    <router-link to="/about">About</router-link>
    <router-link to="/products">商品一覧</router-link>
    <router-link to="/contact">お問合せ</router-link>
  </nav>
  <router-view />
</template>

<style>
nav a {
  color: #64748b;
  text-decoration: none;
  padding: 8px 16px;
}

/* 現在ページのハイライト */
nav a.router-link-active {
  color: #f4c430;
  font-weight: bold;
  border-bottom: 2px solid #f4c430;
}

/* 完全一致 (/ にいるときのトップだけ) */
nav a.router-link-exact-active {
  background-color: #fffbea;
}
</style></code></pre>
<p>これだけで <code>/about</code> にいるときに "About" だけがハイライトされます。</p>

<h2>active と exact-active の違い</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>現在 URL</th><th>リンク to="/"</th><th>リンク to="/products"</th></tr></thead>
<tbody>
<tr><td><code>/</code></td><td>active + exact-active</td><td>-</td></tr>
<tr><td><code>/products</code></td><td>active</td><td>active + exact-active</td></tr>
<tr><td><code>/products/123</code></td><td>active</td><td>active のみ (exact 不一致)</td></tr>
</tbody>
</table>

<p>つまり <code>router-link-active</code> は<strong>前方一致</strong>、<code>router-link-exact-active</code> は<strong>完全一致</strong>です。</p>

<h2>クラス名のグローバル変更</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// router/index.js (Vue Router 4)
import { createRouter, createWebHistory } from &apos;vue-router&apos;;

const router = createRouter({
  history: createWebHistory(),
  routes: [/* ... */],
  linkActiveClass: &apos;is-active&apos;,
  linkExactActiveClass: &apos;is-current&apos;,
});

export default router;</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-css">/* CSS 側もこれで参照 */
nav a.is-active { color: #f4c430; }
nav a.is-current { background: #fffbea; }</code></pre>
<h2>リンク単位のカスタマイズ</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-vue"><router-link to="/about" active-class="my-active" exact-active-class="my-exact">
  About
</router-link></code></pre>
<h2>computed + $route で完全制御</h2>

<p>サブメニュー / ボタン / フッターなど <code><router-link></code> 以外の要素でハイライトしたい場合:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-vue"><template>
  <nav>
    <button
      :class="{ active: isActive(&apos;/&apos;) }"
      @click="$router.push(&apos;/&apos;)"
    >トップ</button>

    <button
      :class="{ active: isActive(&apos;/about&apos;) }"
      @click="$router.push(&apos;/about&apos;)"
    >About</button>

    <button
      :class="{ active: isActive(&apos;/products&apos;) }"
      @click="$router.push(&apos;/products&apos;)"
    >商品</button>
  </nav>
</template>

<script setup>
import { computed } from &apos;vue&apos;;
import { useRoute } from &apos;vue-router&apos;;

const route = useRoute();

function isActive(path) {
  return route.path === path
      || route.path.startsWith(path + &apos;/&apos;);
}
</script>

<style scoped>
button.active {
  color: #f4c430;
  font-weight: bold;
}
</style></code></pre>
<h2>ネストルートでの挙動</h2>

<p>子ルートにいるとき親リンクも active になります:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// routes
{
  path: &apos;/products&apos;,
  component: ProductsLayout,
  children: [
    { path: &apos;&apos;, component: ProductsIndex },
    { path: &apos;:id&apos;, component: ProductDetail },
  ],
}

// /products/123 にいるとき
// <router-link to="/products"> は router-link-active が付く (前方一致)
// <router-link to="/products/123"> は exact-active も付く</code></pre>
<h2>動的なルートに対する判定</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-vue"><template>
  <ul>
    <li v-for="cat in categories" :key="cat.id">
      <router-link :to="`/category/${cat.slug}`">
        {{ cat.name }}
      </router-link>
    </li>
  </ul>
</template>

<script setup>
import { computed } from &apos;vue&apos;;
import { useRoute } from &apos;vue-router&apos;;

const route = useRoute();

const currentSlug = computed(() => route.params.slug);
</script></code></pre>
<h2>Nuxt 3 の場合</h2>

<p>Nuxt 3 は <code><NuxtLink></code> が同等の動作をします。クラス名も同じ <code>router-link-active</code> / <code>router-link-exact-active</code>:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-vue"><template>
  <nav>
    <NuxtLink to="/">トップ</NuxtLink>
    <NuxtLink to="/about">About</NuxtLink>
  </nav>
</template>

<style>
.router-link-active { color: #f4c430; }
.router-link-exact-active { background: #fffbea; }
</style></code></pre>
<p>Nuxt 3.4+ では <code>activeClass</code> / <code>exactActiveClass</code> プロップで変更可能:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-vue"><NuxtLink to="/about" active-class="my-active">About</NuxtLink></code></pre>
<h2>クエリパラメータ違いを区別したい</h2>

<p>標準の active 判定はパスのみ。クエリも含めたい場合は手動:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-vue"><template>
  <router-link
    to="/search?cat=book"
    :class="isActiveWithQuery(&apos;/search&apos;, { cat: &apos;book&apos; }) ? &apos;active&apos; : &apos;&apos;"
  >書籍</router-link>
</template>

<script setup>
import { useRoute } from &apos;vue-router&apos;;
const route = useRoute();

function isActiveWithQuery(path, query) {
  if (route.path !== path) return false;
  return Object.entries(query).every(([k, v]) => route.query[k] === v);
}
</script></code></pre>
<h2>CSS で表現の工夫</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-css">/* 下線で示す */
nav a.router-link-active {
  position: relative;
}
nav a.router-link-active::after {
  content: &apos;&apos;;
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: #f4c430;
}

/* バッジで示す */
nav a.router-link-exact-active::before {
  content: &apos;●&apos;;
  color: #f4c430;
  margin-right: 4px;
}

/* スムーズなトランジション */
nav a {
  transition: color .2s, border-color .2s;
}</code></pre>
<h2>FAQ</h2>

<p><strong>Q: <code>/</code> リンクが全ページで active になる</strong><br />
A: 旧 Vue Router 3 の挙動。<code>exact</code> プロップを付けるか、Vue Router 4 にアップグレード (4 では exact-active が独立クラス化)。</p>

<p><strong>Q: ハイライトが付かない</strong><br />
A: <code><router-link></code> が描画する <code><a></code> 要素にクラスが付く。CSS で <code>nav a.router-link-active</code> のようにセレクタを正しく指定。</p>

<p><strong>Q: SSR / Hydration で初期表示時にハイライトが消える</strong><br />
A: Nuxt 3 / Vue Router 4 のサーバ側も <code>useRoute()</code> を解決するので問題なし。ハイライトが消える場合は CSS のスコープ問題を疑う。</p>

<p><strong>Q: アンカーリンク (<code>#section</code>) もハイライトしたい</strong><br />
A: ハッシュは <code>route.hash</code> で取れる。<code>:class="{ active: route.hash === "#section" }"</code> で判定。</p>