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

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

この記事の要点
  • Vue Router 利用時は <router-link> が自動付与する router-link-active / router-link-exact-active CSS クラスを利用
  • カスタムクラス名createRouterlinkActiveClass / linkExactActiveClass オプション
  • 個別 <router-link>active-class="..." を渡せばその要素だけ別クラス
  • computed + $route.path:class バインドする手法も汎用的
  • Nuxt 3 は <NuxtLink> が同じ動作。router-link-active がそのまま使える

Vue Router のデフォルト挙動

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

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

最小構成

<!-- 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>

これだけで /about にいるときに "About" だけがハイライトされます。

active と exact-active の違い

現在 URLリンク to="/"リンク to="/products"
/active + exact-active-
/productsactiveactive + exact-active
/products/123activeactive のみ (exact 不一致)

つまり router-link-active前方一致router-link-exact-active完全一致です。

クラス名のグローバル変更

// router/index.js (Vue Router 4)
import { createRouter, createWebHistory } from 'vue-router';

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

export default router;
/* CSS 側もこれで参照 */
nav a.is-active { color: #f4c430; }
nav a.is-current { background: #fffbea; }

リンク単位のカスタマイズ

<router-link to="/about" active-class="my-active" exact-active-class="my-exact">
  About
</router-link>

computed + $route で完全制御

サブメニュー / ボタン / フッターなど <router-link> 以外の要素でハイライトしたい場合:

<template>
  <nav>
    <button
      :class="{ active: isActive('/') }"
      @click="$router.push('/')"
    >トップ</button>

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

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

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

const route = useRoute();

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

<style scoped>
button.active {
  color: #f4c430;
  font-weight: bold;
}
</style>

ネストルートでの挙動

子ルートにいるとき親リンクも active になります:

// routes
{
  path: '/products',
  component: ProductsLayout,
  children: [
    { path: '', component: ProductsIndex },
    { path: ':id', component: ProductDetail },
  ],
}

// /products/123 にいるとき
// <router-link to="/products"> は router-link-active が付く (前方一致)
// <router-link to="/products/123"> は exact-active も付く

動的なルートに対する判定

<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 'vue';
import { useRoute } from 'vue-router';

const route = useRoute();

const currentSlug = computed(() => route.params.slug);
</script>

Nuxt 3 の場合

Nuxt 3 は <NuxtLink> が同等の動作をします。クラス名も同じ router-link-active / router-link-exact-active:

<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>

Nuxt 3.4+ では activeClass / exactActiveClass プロップで変更可能:

<NuxtLink to="/about" active-class="my-active">About</NuxtLink>

クエリパラメータ違いを区別したい

標準の active 判定はパスのみ。クエリも含めたい場合は手動:

<template>
  <router-link
    to="/search?cat=book"
    :class="isActiveWithQuery('/search', { cat: 'book' }) ? 'active' : ''"
  >書籍</router-link>
</template>

<script setup>
import { useRoute } from 'vue-router';
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>

CSS で表現の工夫

/* 下線で示す */
nav a.router-link-active {
  position: relative;
}
nav a.router-link-active::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: #f4c430;
}

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

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

FAQ

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

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

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

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