WEB制作、マーケティングに関する情報をお届けします。ホームページ制作会社、テラのブログ

Javascriptでスクロール領域に合わせてメニューにクラスを追加

タグ:

ランディングページなどの縦に長いサイトでよく使用されるスクロールの領域に合わせてメニューが変化するサイト。
各セクションにIDを振りスクロールで範囲に入ったのを把握してメニューにクラスを付与することで簡単に実装が可能です。本記事ではその方法を紹介します。

コードの紹介

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>スクロールでクラスを追加</title>
</head>
<body>
<!-- スクロールでクラスが追加される要素 -->
<nav class="fixed_banner">
<ul>
<li>セクション1</li>
<li>セクション2</li>
<li>セクション3</li>
<li>セクション4</li>
</ul>
</nav>
<div class="section_wrap">
<!-- セクション1 -->
<div id="sec01"><span>セクション1</span></div>
<!-- セクション2 -->
<div id="sec02"><span>セクション2</span></div>
<!-- セクション3 -->
<div id="sec03"><span>セクション3</span></div>
<!-- セクション4 -->
<div id="sec04"><span>セクション4</span></div>
<!-- フッター -->
<footer id="footer"><span>フッター</span></footer>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
<script>
$(document).ready(function() {
var offset = -100; // オフセット値を設定、-100px調整用
// ウィンドウのスクロールイベントを監視
$(window).on('scroll', function() {
var scrollPos = $(window).scrollTop() + $(window).height() + offset; // 現在のスクロール位置を計算
var banner = $('.fixed_banner'); // クラスを追加する要素を選択
var classList = ''; // 追加するクラス名を保持する変数
// IDを持つ全ての<div><footer>要素を繰り返し処理
$('div[id], footer[id]').each(function() {
var element = $(this); // 現在の要素を取得
var elementTop = element.offset().top; // 現在の要素の上端位置を取得
// 現在のスクロール位置が要素の上端位置を超えた場合
if (scrollPos >= elementTop) {
classList += element.attr('id') + ' '; // 要素のIDをクラスリストに追加
}
});
// .fixed_banner要素にクラスリストを設定
banner.attr('class', 'fixed_banner ' + classList.trim());
});
});
</script>
<style>
body{
font-weight: bold;
width: 100%;
margin: 0 auto;
}
.section_wrap > *{
height: 800px;
color: #FFF;
line-height: 800px;
text-align: center;
width: 100%;
}
#sec01{
background: #1fa046;
}
#sec02{
background: #d0462c;
}
#sec03{
background: #3f68af;
}
#sec04{
background: #cd9100;
}
footer{
background: #000000;
}
.fixed_banner {
position: fixed;
top: 0;
width: 100%;
background: #FFF;
z-index: 1000;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 5px 0 rgba(0, 0, 0, .08)
}
.fixed_banner ul{
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
.fixed_banner ul li{
margin-right: 20px;
transition: 0.3s;
}
.fixed_banner.sec01 ul li:nth-child(1),
.fixed_banner.sec02 ul li:nth-child(2),
.fixed_banner.sec03 ul li:nth-child(3),
.fixed_banner.sec04 ul li:nth-child(4){
color: #ff0000;
}
.fixed_banner.sec01.footer ul li:nth-child(1),
.fixed_banner.sec02.footer ul li:nth-child(2),
.fixed_banner.sec03.footer ul li:nth-child(3),
.fixed_banner.sec04.footer ul li:nth-child(4){
color: #000000;
}
</style>
</body>
</html>
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>スクロールでクラスを追加</title> </head> <body> <!-- スクロールでクラスが追加される要素 --> <nav class="fixed_banner"> <ul> <li>セクション1</li> <li>セクション2</li> <li>セクション3</li> <li>セクション4</li> </ul> </nav> <div class="section_wrap"> <!-- セクション1 --> <div id="sec01"><span>セクション1</span></div> <!-- セクション2 --> <div id="sec02"><span>セクション2</span></div> <!-- セクション3 --> <div id="sec03"><span>セクション3</span></div> <!-- セクション4 --> <div id="sec04"><span>セクション4</span></div> <!-- フッター --> <footer id="footer"><span>フッター</span></footer> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script> <script> $(document).ready(function() { var offset = -100; // オフセット値を設定、-100px調整用 // ウィンドウのスクロールイベントを監視 $(window).on('scroll', function() { var scrollPos = $(window).scrollTop() + $(window).height() + offset; // 現在のスクロール位置を計算 var banner = $('.fixed_banner'); // クラスを追加する要素を選択 var classList = ''; // 追加するクラス名を保持する変数 // IDを持つ全ての<div>と<footer>要素を繰り返し処理 $('div[id], footer[id]').each(function() { var element = $(this); // 現在の要素を取得 var elementTop = element.offset().top; // 現在の要素の上端位置を取得 // 現在のスクロール位置が要素の上端位置を超えた場合 if (scrollPos >= elementTop) { classList += element.attr('id') + ' '; // 要素のIDをクラスリストに追加 } }); // .fixed_banner要素にクラスリストを設定 banner.attr('class', 'fixed_banner ' + classList.trim()); }); }); </script> <style> body{ font-weight: bold; width: 100%; margin: 0 auto; } .section_wrap > *{ height: 800px; color: #FFF; line-height: 800px; text-align: center; width: 100%; } #sec01{ background: #1fa046; } #sec02{ background: #d0462c; } #sec03{ background: #3f68af; } #sec04{ background: #cd9100; } footer{ background: #000000; } .fixed_banner { position: fixed; top: 0; width: 100%; background: #FFF; z-index: 1000; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 5px 0 rgba(0, 0, 0, .08) } .fixed_banner ul{ display: flex; justify-content: space-around; flex-wrap: wrap; } .fixed_banner ul li{ margin-right: 20px; transition: 0.3s; } .fixed_banner.sec01 ul li:nth-child(1), .fixed_banner.sec02 ul li:nth-child(2), .fixed_banner.sec03 ul li:nth-child(3), .fixed_banner.sec04 ul li:nth-child(4){ color: #ff0000; } .fixed_banner.sec01.footer ul li:nth-child(1), .fixed_banner.sec02.footer ul li:nth-child(2), .fixed_banner.sec03.footer ul li:nth-child(3), .fixed_banner.sec04.footer ul li:nth-child(4){ color: #000000; } </style> </body> </html>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>スクロールでクラスを追加</title>
</head>
<body>
    <!-- スクロールでクラスが追加される要素 -->
    <nav class="fixed_banner">
        <ul>
            <li>セクション1</li>
            <li>セクション2</li>
            <li>セクション3</li>
            <li>セクション4</li>
        </ul>
    </nav>

    <div class="section_wrap">
        <!-- セクション1 -->
        <div id="sec01"><span>セクション1</span></div>
        <!-- セクション2 -->
        <div id="sec02"><span>セクション2</span></div>
        <!-- セクション3 -->
        <div id="sec03"><span>セクション3</span></div>
        <!-- セクション4 -->
        <div id="sec04"><span>セクション4</span></div>
        <!-- フッター -->
        <footer id="footer"><span>フッター</span></footer>
    </div>
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
    <script>
        $(document).ready(function() {
            var offset = -100; // オフセット値を設定、-100px調整用
    
            // ウィンドウのスクロールイベントを監視
            $(window).on('scroll', function() {
                var scrollPos = $(window).scrollTop() + $(window).height() + offset; // 現在のスクロール位置を計算
                var banner = $('.fixed_banner'); // クラスを追加する要素を選択
                var classList = ''; // 追加するクラス名を保持する変数
    
                // IDを持つ全ての<div>と<footer>要素を繰り返し処理
                $('div[id], footer[id]').each(function() {
                    var element = $(this); // 現在の要素を取得
                    var elementTop = element.offset().top; // 現在の要素の上端位置を取得
    
                    // 現在のスクロール位置が要素の上端位置を超えた場合
                    if (scrollPos >= elementTop) {
                        classList += element.attr('id') + ' '; // 要素のIDをクラスリストに追加
                    }
                });
    
                // .fixed_banner要素にクラスリストを設定
                banner.attr('class', 'fixed_banner ' + classList.trim());
            });
        }); 
    </script>
<style>
body{
    font-weight: bold;
    width: 100%;
    margin: 0 auto;
}
.section_wrap > *{
    height: 800px;
    color: #FFF;
    line-height: 800px;
    text-align: center;
    width: 100%;
}
#sec01{
    background: #1fa046;
}
#sec02{
    background: #d0462c;
}
#sec03{
    background: #3f68af;
}
#sec04{
    background: #cd9100;
}
footer{
    background: #000000;
}
.fixed_banner {
    position: fixed;
    top: 0;
    width: 100%;
    background: #FFF;
    z-index: 1000;
    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .1), 0 1px 5px 0 rgba(0, 0, 0, .08)
}
.fixed_banner ul{
    display: flex;
    justify-content: space-around;
    flex-wrap: wrap;
}
.fixed_banner ul li{
    margin-right: 20px;
    transition: 0.3s;
}
.fixed_banner.sec01 ul li:nth-child(1),
.fixed_banner.sec02 ul li:nth-child(2),
.fixed_banner.sec03 ul li:nth-child(3),
.fixed_banner.sec04 ul li:nth-child(4){
    color: #ff0000;
}
.fixed_banner.sec01.footer ul li:nth-child(1),
.fixed_banner.sec02.footer ul li:nth-child(2),
.fixed_banner.sec03.footer ul li:nth-child(3),
.fixed_banner.sec04.footer ul li:nth-child(4){
    color: #000000;
}
</style>
</body>
</html>

コードを解説

HTML、CSSは説明を割愛します。
まず、jqueryを使用しますのでCDNを使用してインクルードします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>

スクロールした際に調整用の数値をセットします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
var offset = -100; // オフセット値を設定、-100px調整用
var offset = -100; // オフセット値を設定、-100px調整用
var offset = -100; // オフセット値を設定、-100px調整用

スクロールで実行させます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$(window).on('scroll', function() {}
$(window).on('scroll', function() {}
$(window).on('scroll', function() {}

スクロール位置の計算、クラスを付与する要素のクラス名を設定、クラスを追加する際に使う変数を宣言しておきます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
var scrollPos = $(window).scrollTop() + $(window).height() + offset; // 現在のスクロール位置を計算
var banner = $('.fixed_banner'); // クラスを追加する要素を選択
var classList = ''; // 追加するクラス名を保持する変数
var scrollPos = $(window).scrollTop() + $(window).height() + offset; // 現在のスクロール位置を計算 var banner = $('.fixed_banner'); // クラスを追加する要素を選択 var classList = ''; // 追加するクラス名を保持する変数
var scrollPos = $(window).scrollTop() + $(window).height() + offset; // 現在のスクロール位置を計算
var banner = $('.fixed_banner'); // クラスを追加する要素を選択
var classList = ''; // 追加するクラス名を保持する変数

『id』を持つdiv要素、footer要素で繰り返しの処理を行います。
各セクションが表示領域に入ったらメニューにクラス名が付与されます。
また、ID名を取得してそのままメニューにクラス名として付与していますので、コードも省きます。
CSSでの定義はそれを考慮して行なってください。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// IDを持つ全ての<div>と<footer>要素を繰り返し処理
$('div[id], footer[id]').each(function() {
var element = $(this); // 現在の要素を取得
var elementTop = element.offset().top; // 現在の要素の上端位置を取得
// 現在のスクロール位置が要素の上端位置を超えた場合
if (scrollPos >= elementTop) {
classList += element.attr('id') + ' '; // 要素のIDをクラスリストに追加
}
});
// IDを持つ全ての<div>と<footer>要素を繰り返し処理 $('div[id], footer[id]').each(function() { var element = $(this); // 現在の要素を取得 var elementTop = element.offset().top; // 現在の要素の上端位置を取得 // 現在のスクロール位置が要素の上端位置を超えた場合 if (scrollPos >= elementTop) { classList += element.attr('id') + ' '; // 要素のIDをクラスリストに追加 } });
// IDを持つ全ての<div>と<footer>要素を繰り返し処理
$('div[id], footer[id]').each(function() {
    var element = $(this); // 現在の要素を取得
    var elementTop = element.offset().top; // 現在の要素の上端位置を取得
    
    // 現在のスクロール位置が要素の上端位置を超えた場合
    if (scrollPos >= elementTop) {
        classList += element.attr('id') + ' '; // 要素のIDをクラスリストに追加
    }
});

スクロール領域から外れたら『attr』に『クラス名.trim()』でクラス名を削除します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// .fixed_banner要素にクラスリストを設定
banner.attr('class', 'fixed_banner ' + classList.trim());
// .fixed_banner要素にクラスリストを設定 banner.attr('class', 'fixed_banner ' + classList.trim());
// .fixed_banner要素にクラスリストを設定
banner.attr('class', 'fixed_banner ' + classList.trim());

まとめ

以上、『Javascriptでスクロール領域に合わせてメニューにクラスを追加』でした。
今回の方法はメニューでも使えますが、コンテンツ量の多いオウンドメディアなどで目次として追従させることもできますのでユーザビリティーの向上にも使用できるでしょう。
また、クラス名を付与しているだけなのでCSSでアニメーションを設定すれば動きも自由に設定できるので使い勝手もいいと思います。
ぜひ、参考にしてみてください。

テラ合同会社(東京都)

テラは2014年に東京都でスタートアップしたホームページ制作会社です。ホームページ制作以外にも広告運用、マーケティング、ブランディング、印刷物など幅広い領域をサポートしています。
コーポレートサイトはこちらをご覧ください。