記事ページでナビの現在地が消える — カレント表示を1か所で決める | GH Media
URLがコピーされました

記事ページでナビの現在地が消える — カレント表示を1か所で決める

URLがコピーされました
記事ページでナビの現在地が消える — カレント表示を1か所で決める

サイトの検収でほぼ必ず出る指摘があります。「一覧ページではグローバルナビの『メディア』が光るのに、記事の詳細ページに入ると消える」。

軽微な見た目の問題に見えますが、直すとなると意外に長引きます。多くのサイトで、この現在地の判定がテンプレート・JavaScript・CSS の3か所に散らばっているからです。1か所を直すと別のページで壊れる、という往復が始まります。

CSS 側でこれを宣言的に解こうとする提案が W3C で動き始めています。ただし、いま作っているサイトで使えるものではありません。使えるようになるまでの間、判定をどこに置くかという設計の話になります。

一致判定が毎回バグる4つの場所

「今いるページと同じURLのリンクを光らせる」という要件は一行ですが、実装では次の分岐に必ずぶつかります。

1. 末尾スラッシュ。 /media/media/ を文字列で比較すると一致しません。サイトの設定でどちらかに寄せていても、リンクの書き方が揃っていなければ判定は割れます。

2. 階層下のページ。 /media/0123-example/ を開いているとき、ナビの「メディア」は光らせたい。完全一致では光りません。前方一致にすると、今度は /service//services-list/ のような紛らわしいパスまで巻き込みます。

3. ページ送り。 /media/tech/2/ のようなページネーションで、カテゴリのリンクを光らせるかどうか。ここは仕様として決めておかないと、実装者の判断で揺れます。

4. クエリとフラグメント。 ?page=2#section が付いたときに一致とみなすか。検索結果や絞り込みを持つサイトでは、ここで表示がちらつきます。

4つとも「どちらが正しい」という答えはなく、サイトごとに決めるべき仕様です。 にもかかわらず要件書には書かれないため、実装者が都度その場で決め、結果として判定が散らばります。

CSS だけで解こうとする提案は、まだ早い

この痛点は古くから知られていて、CSS 側にも :local-link という擬似クラスが用意されています。現在の文書URLと一致するリンクを表す、まさにこの用途のためのものです。Selectors 4 に再導入され、仕様としては現行です。

ただし、実装しているブラウザはまだありません。

その先の動きとして、Chrome で宣言的なルート/ナビゲーションマッチングの検討が進んでいます。@navigation で名前付きのルートを定義し、:link-to(--detail) のようにリンク先で選択する、という方向です。ルートの指定には url-pattern() も使えます。2026年1月に CSS Working Group で紹介され、6月の CSS Day でのフィードバックを経て、ベルリンの F2F で議論される段階にあります。

方向性としては、上に挙げた4つの分岐をパターンマッチとして宣言的に書けるようにするものです。前方一致もパラメータ付きのルートも、JavaScript を書かずに表現できるようになります。

一方で、パラメータ一致(特定の id を持つルートへのリンクだけを選ぶ、といった指定)はまだ検討中で、仕様も実装もこれからです。今つくっているサイトの実装方針を、この提案を前提に決めることはできません。

いま取る形は「判定を1か所に寄せる」

実装済みの手段だけで組むなら、方針は単純です。一致判定はサーバー側かテンプレート側で一度だけ行い、結果を aria-current 属性として出力する。CSS はその属性を見て装飾するだけにする。

---
// 判定ロジックはここ1か所に置く
const path = Astro.url.pathname.replace(/\/?$/, "/"); // 末尾スラッシュを揃える

// そのページ自身か
const isPage = (href: string) => path === href;
// その配下にいるか(/service/ と /services-list/ を取り違えないよう区切りまで見る)
const isSection = (href: string) => path === href || path.startsWith(href);
---
<a href="/media/" aria-current={isPage("/media/") ? "page" : undefined}
   data-section={isSection("/media/") ? "" : undefined}>
  メディア
</a>
nav a[aria-current="page"] {
  color: var(--color-accent);
  border-bottom: 2px solid currentColor;
}

/* 配下ページでは、意味づけを伴わない弱い装飾にとどめる */
nav a[data-section] {
  color: var(--color-accent);
}

href の末尾スラッシュを揃えておけば、startsWith/service//services-list/ を巻き込むことはありません。「末尾スラッシュを揃える」という前処理を1行入れておくかどうかで、前方一致が使える判定になるかどうかが決まります。

この形にする利点は3つあります。

判定の置き場所が1つに決まります。 仕様が変わったとき(ページ送りも光らせたい、など)に直す場所が1か所です。散らばった状態でこの変更依頼が来ると、修正範囲の見積もりが立ちません。

スクリーンリーダーに現在地が伝わります。 色や下線だけの実装では、視覚的に見ている人にしか現在地が分かりません。aria-current="page" は「これが現在のページです」という意味そのものを伝える属性です。装飾と意味を分けて考える話はCustom Highlight APIでハイライトを入れる場合でも同じ構図で出てきます。

JavaScript が要りません。 現在地表示のためだけにクライアント側のスクリプトを積む必要がなくなります。要らなくなったJavaScriptがサイトを重くする話はサイトが重い原因にまとめました。

判定をテンプレート1か所に集約し、CSSは属性を見て装飾するだけにする構成の図

なお、aria-current="page" を付けてよいのはまさにそのページ自身へのリンクです。記事詳細ページで親カテゴリのリンクを光らせたい場合、それは「現在のページ」ではありません。装飾用のクラスや data- 属性で分けておくのが無難です。ここを混ぜると、読み上げ環境では「現在のページ」が2つあるように聞こえます。

要件として書いておく一行

発注や仕様確定の段階で、次の一行を要件書に足しておくと、実装後の往復が減ります。

グローバルナビの現在地表示は、詳細ページ・ページ送り・絞り込み時にどう振る舞うかを含めて定義する。

この一行があれば、上の4つの分岐は実装前に決まります。ない場合、決まるのは検収の指摘が出た後です。制作会社との間で実装標準をどこまで握っておくかという話はState of CSS 2026を発注側が読み解くにも書きました。

次にやること

運用中のサイトがあるなら、記事の詳細ページを1枚開いて、グローバルナビの現在地表示が意図どおりかを確認してください。 消えている場合、判定が完全一致になっている可能性が高く、修正自体は小さく済みます。

これから作る、あるいはリニューアルする場合は、現在地の判定をテンプレート側の関数1つに寄せ、出力を aria-current に統一する方針を最初に決めてください。 将来 CSS 側の宣言的な仕組みが使えるようになったとき、置き換える対象がその関数1つで済みます。

サイトの実装標準の整備、既存サイトのアクセシビリティ改修、フロントエンドの設計見直しについては、グリームハブの開発・AI・自動化のご相談で承っています。既存実装の構成によって改修範囲が変わるため、個別にご相談ください。お問い合わせからどうぞ。

Sources

無料ダウンロード

Web制作 費用・発注・集客 完全ガイド【2026年版】

費用相場・制作会社の選び方・集客戦略まで、中小企業のWeb担当者が知っておくべき全知識をPDFにまとめました。

メルマガにも登録されます。いつでも解除可能です。

URLがコピーされました

グリームハブ株式会社は、変化の激しい時代において、アイデアを形にし、人がもっと自由に、もっと創造的に生きられる世界を目指しています。

記事を書いた人

鈴木 翔

鈴木 翔

技術の可能性に魅了され、学生時代からプログラミングとデジタルアートの分野に深い関心を持つ

関連記事

「WEB」の記事一覧を見る