閲覧中のページURLに応じてナビゲーションにカレントのスタイルを設定する実装をメモ。
サンプルコード
今回は以下の2パターンを実装してみます。
- 閲覧中のURLが対象のナビゲーションのディレクトリ配下の場合にスタイルを設定するパターン(ヘッダーナビなど)
- 閲覧中のURLと一致するナビゲーションにスタイルを設定するパターン(ローカルナビなど)
まず一つ目のパターンの想定で、ヘッダーのナビを追加します。
JavaScriptでの制御用に、各ナビにjs-nav-dir-currentというclassを付与しておきます。
<header class="header">
<nav class="nav">
<ul class="nav-list">
<li class="nav-item js-nav-dir-current">
<a href="/about/">会社概要</a>
</li>
<li class="nav-item js-nav-dir-current">
<a href="/service/">サービス</a>
</li>
<li class="nav-item js-nav-dir-current">
<a href="/contact/">お問い合わせ</a>
</li>
<li class="nav-item js-nav-dir-current">
<a href="/blog/">ブログ</a>
</li>
</ul>
</nav>
</header>
二つ目のパターンの想定で、about ディレクトリ(会社概要)内にローカルナビを追加します。
先ほどと同様に、各ナビにjs-nav-path-currentという別のclassを付与しておきます。
<nav class="side-nav">
<ul class="sidenav-list">
<li class="sidenav-item js-nav-path-current">
<a href="/about/index.html">会社概要</a>
</li>
<li class="sidenav-item js-nav-path-current">
<a href="/about/messages.html">メッセージ</a>
</li>
<li class="sidenav-item js-nav-path-current">
<a href="/about/vision/">経営理念</a>
</li>
<li class="sidenav-item js-nav-path-current">
<a href="/about/vision/mission/">ミッション</a>
</li>
<li class="sidenav-item js-nav-path-current">
<a href="/about/history.html">沿革</a>
</li>
<li class="sidenav-item js-nav-path-current">
<a href="/about/location.html">所在地</a>
</li>
</ul>
</nav>
カレントの場合はis-currentというclassが付与されるようにするので、そのスタイルを用意しておきます。
.nav-item.is-current a {
color: red;
}
.sidenav-item.is-current a {
color: red;
}
最後にJavaScriptでの実装です。
document.addEventListener('DOMContentLoaded', () => {
setCurrentToMatchPathNav();
setCurrentToMatchDirNav();
});
/*
* ページURLと一致するナビゲーションにカレントを付与する
*/
function setCurrentToMatchPathNav() {
// 調整したページURLを取得
const pageDir = adjustPageDisplay(window.location.pathname);
// 対象のナビゲーションのうち、ページURLと一致するものにカレントを付与する
const navItems = document.querySelectorAll('.js-nav-path-current');
navItems.forEach(item => {
const itemLink = item.querySelector('a');
if (!itemLink) return;
const itemLinkPathname = new URL(itemLink.href).pathname;
const itemLinkDir = adjustPageDisplay(itemLinkPathname);
if (itemLinkDir === pageDir) {
item.classList.add('is-current');
}
});
}
/*
* ページURLが対象のナビゲーションのディレクトリ配下の場合にカレントを付与する
*/
function setCurrentToMatchDirNav() {
// 調整したページURLを取得
const pageDir = adjustPageDisplay(window.location.pathname, false);
// 対象のナビゲーションのうち、ページURLと先頭から途中まで一致するものにカレントを付与する
const navItems = document.querySelectorAll('.js-nav-dir-current');
navItems.forEach(item => {
const itemLink = item.querySelector('a');
if (!itemLink) return;
const itemLinkPathname = new URL(itemLink.href).pathname;
const itemLinkDir = adjustPageDisplay(itemLinkPathname, false);
if (pageDir.startsWith(itemLinkDir)) {
item.classList.add('is-current');
}
});
}
/*
* ページURLの調整
* @param {string} dir ページURL
* @param {boolean} filename ファイル名を含めるかどうか
* @returns {string} 調整後のページURL
*/
function adjustPageDisplay(dir, filename = true) {
// ディレクトリの末尾にファイル名(htmlファイル)がない場合はindex.htmlを付与する
if (filename && !dir.endsWith('.html')) {
if (!dir.endsWith('/')) dir += '/';
dir += 'index.html';
}
return dir;
}
コメントが承認されるまで時間がかかります。