WORKS

スクロール連動ナビゲーション
HTML5/CSS3
Javascript
WEBページによく見られる、スクロールに連動してナビゲーションの項目にアクションが起きるものです。職業訓練校の朝礼用に作成しました。
サンプルページ01(PC専用)>>
INDEX
サンプル
今回ご紹介するのは、画面スクロールに連動して、ナビゲーションメニューのデザインを変える方法です。連動させるナビゲーションをposition:fixedやposition:stickyなどで画面に固定して使います。セクションの切り替わりに合わせてメニューが目立ってくれるので、UIとしても分かりやすいです。

私が調べたところ、実装する方法は2種類ありました。jQueryのスクロールイベントを用いる方法と、intersection observer(交差監視)というAPI(あるソフトウェアの機能を別のソフトウェアから呼び出す仕組み)を用いる方法です。今回はより簡易に実装できるjQueryのスクロールイベントを用いる方法をご紹介してから、最後におまけでintersection observer APIについて少しだけ触れようと思います。
HTML
HTMLはいたってシンプルです。ナビゲーションとなるリストにaタグを記述し、各コンテンツのブロック要素にidを指定してページ内リンクを付与します。このとき紐づけされたリストとコンテンツが、そのままスクロールに連動するようになります。
<main>
<aside>
<ul id="indexList">
<li><a href="#sec01">sec01</a></li>
<li><a href="#sec02">sec02</a></li>
<li><a href="#sec03">sec03</a></li>
<li><a href="#sec04">sec04</a></li>
<li><a href="#sec05">sec05</a></li>
</ul>
</aside>
<div class="contents">
<section id="sec01" class="box">sec01</section>
<section id="sec02" class="box">sec02</section>
<section id="sec03" class="box">sec03</section>
<section id="sec04" class="box">sec04</section>
<section id="sec05" class="box">sec05</section>
</div>
</main>
CSS
スクロール連動部分を分かりやすくするため、その他デザインは単純な仕様とします。スクロール連動アクションについても、今回は該当するメニューの背景色を変更するだけにします。
#indexList a.active {
background-color: orange;
}
Javascript
まずは全体を記述します。大まかなイメージとしては、ウィンドウのスクロール値を取得して、お目当てのセクションまでスクロールされれば、リンクするナビメニューにcssクラスをつける、といった流れになります。
$(function () {
$(window).on("load scroll resize", function () {
let scrolll = $(window).scrollTop();
let windowHeight= $(window).height();
$('.box').each(function () {
let target = $(this).offset().top;
let idName = $(this).attr("id");
if (scroll > target - windowHeight + (windowHeight / 2)) {
$("#indexList a").removeClass("active");
let link = $("#indexList a[href *= " + idName +"]");
$(link).addClass("active");
}
});
});
});
+α intersection observer
intersection observerというAPIで実装したものです。jQueryが主に画面スクロールをトリガーにして動いていたのに対して、こちらは対象のセクションが画面端に交差したことをトリガーに動きます。
jQueryと違い、何度もスクロール値を取得することがないので、その分動きが軽くなります。
サンプルページ02(PC専用)>>// 交差を監視する要素を配列の中にセット
const boxes = document.querySelectorAll(".box");
// Intersection Observerの設定
const options = {
root: null,
rootMargin: "0px",
threshold: 0.5
};
// Intersection Observerを使えるようにする
const observer = new IntersectionObserver(intersect, options);
// 対象(準備した配列内)の要素をそれぞれ監視する
boxes.forEach(box => {
observer.observe(box);
});
// 交差したときに実行する関数
function intersect(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) { // 監視中の要素が交差した状態ならtrueになる
// 監視中の要素が交差したときの処理
activateIndex(entry.target);
}
});
}
// メニューの色を変える関数
function activateIndex(element) {
// すでにアクティブになっている目次を選択
const currentActiveIndex = document.querySelector("#indexList .active");
// すでにアクティブになっているものが0個の時(=null)以外は、activeクラスを除去
if (currentActiveIndex !== null) {
currentActiveIndex.classList.remove("active");
}
// 引数で渡されたDOMが飛び先のaタグを選択し、activeクラスを付与
const newActiveIndex = document.querySelector(`a[href='#${element.id}']`);
newActiveIndex.classList.add("active");
}