グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



【jQuery】ページ内のどのコンテンツにいるのか分かるエレベーターメニューを実装してみた

最近のwebサイトではエレベーターメニューをよく見るようになりました。
LPなど長いページでの使用や、沿革ページで年ごとに区分するなど、使い方は様々です。

今回はjQueryを使って、エレベーターメニューを実装してみたいと思います。

エレベーターメニューの仕様

最初に、エレベーターメニューの仕様について考えていきます。

エレベーターメニューを設置する利点は、ページ内にコンテンツがどのくらい存在し、現在そのどこに位置しているかが把握できること。そしてそれらのコンテンツに常にアクセスできるという点です。

なので、第一にフローティングしクリックすると遷移するボタンであることが挙げられます。
ページ内を移動するという機能をより明確にするため、クリックした後の挙動は滑らかに遷移することがユーザー体験としては理想です。

次に、現在位置が把握できること
メニューボタンの数とその移動先のコンテンツを対応させて、コンテンツが画面に表示されたらボタンを変化させる必要があります。

そして、エレベーターメニュー外に出たらカレントを解除すること
サイトにはイントロ部分やフッターといった、主要コンテンツ以外のセクションが存在しているはずなので、主要コンテンツ以外はエレベーターメニューのカレントは解除するというところまで考えていきます。

以上、三つの点がエレベーターメニューの仕様となります。

HTMLとCSSの記述

ではここからは実際に記述していきます。

まずはHTMLとCSSでメニュー部分とコンテンツ部分を実装していきます。

メニュー部分の記述は下記になります。

<div class="elevator-menu__wrap">
    <ul class="elevator-menu__lists">
        <li class="elevator-menu__list">
            <a href="#el001" class="elevator-menu__link">content001</a>
        </li>
        <li class="elevator-menu__list">
            <a href="#el002" class="elevator-menu__link">content002</a>
        </li>
        <li class="elevator-menu__list">
            <a href="#el003" class="elevator-menu__link">content003</a>
        </li>
        <li class="elevator-menu__list">
            <a href="#el004" class="elevator-menu__link">content004</a>
        </li>
    </ul>
</div>
.elevator-menu__wrap {
    position: fixed;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    z-index: 10;
}
.elevator-menu__lists {
    display: flex;
    flex-direction: column;
    gap: 20px;
}
.elevator-menu__list {
    width: 16px;
    height: 16px;
}
.elevator-menu__link {
    width: 100%;
    height: 100%;
    display: block;
    border-radius: 50%;
    background: #fff;
    text-indent: 200%;
    overflow: hidden;
    text-wrap: nowrap;
    transition: all .3s
}
.elevator-menu__link.active {
    background: #222;
}

position:fixed;で追従させ、display:flex;で縦に並べています。

今回は単純にactiveクラスを追加してボタンの色が変わる仕様にしました。

次にコンテンツ部分の記述です。

<div class="intro">
    イントロ
</div>
<div class="content content001" id="el001">
    コンテンツ1
</div>
<div class="content content002" id="el002">
    コンテンツ2
</div>
<div class="content content003" id="el003">
    コンテンツ3
</div>
<div class="content content004" id="el004">
    コンテンツ4
</div>
<div class="footer">
    フッター
</div>
.intro,.content,.footer {
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 20px;
    font-weight: bold;
    width: 100%;
    height: 1500px;
    background: #ddd;
}
.content001 {
    background: #ffbfbf;
}
.content002 {
    background: #fffbba;
}
.content003 {
    background: #baffc0;
}
.content004 {
    background: #bae9ff;
}

コンテンツの境がわかりやすいように、コンテンツごとに色を変えています。
メニューのリンク先と、コンテンツのIDをしっかり合わせるようにしましょう。

jQueryで滑らかにスクロールさせる

先ほど作成したメニューボタンを押したとき、対象のコンテンツに滑らかに移動するようにjQueryを用いて設定していきます。

$('a[href ^= "#"]').click(function(){
    const href = $(this).attr('href');
    const content = $(href === '#' || href === '' ? html : href );
    $('html, body').animate({scrollTop:content.offset().top}, 400);
});

詳しく見ていきます。

1行目で「#」の文字列と前方一致したhrefを持つaタグをクリックしたら発火させます。
2行目で変数hrefにクリックしたaタグのhref文字列を代入。
3行目で変数contentに変数hrefを代入します。(hrefが「#」のみもしくは空の場合はhtmlが代入されます。)
4行目で、ページ上部からcontentまでの距離を測り、400ミリ秒かけて滑らかに移動します。

このときcontentに代入してある文字列は、クリックしたaタグのhrefの文字列であり、ページ内のコンテンツのIDと一致するので、対象のIDを持つコンテンツまで移動するという仕組みになります。

リンクの個数を調べリンク先のIDを取得

次に、現在地の表示のためにリンク先対象のIDを調べていきます。

const contentArr = [];
const elMenu = $('.elevator-menu__link');
for(let i = 0; i < elMenu.length; i++){
    const elMenuLink = elMenu.eq(i).attr('href');
    contentArr[i] = elMenuLink;
}

contentArr配列にelevator-menu__linkのhrefの文字列を格納していきます。
elevator-menu__linkというのは先ほどのボタンのリンクのことになるので、リンク先のIDを格納してくことになります。

4行目にある.eq(i)は「i番目の」という意味で、for文で0番目から順にリンクの数だけ格納していきます。今回は4つになります。

console.log(contentArr[0],contentArr[1],contentArr[2],contentArr[3]);

console.log()で中を見てみると、

#el001 #el002 #el003 #el004

実際に格納されていることが確認できます。

現在位置を表示

最後にエレベーターメニューの根幹部分の記述をしていきます。

$(window).on('load resize scroll', function(){
    const windowHeightHalf = $(window).height() / 2;
    const position = $(window).scrollTop() + windowHeightHalf;
    for(let i = 0; i < contentArr.length; i++){
        let target = contentArr[i];
        let secTop = $(target).offset().top;
        let secBottom = secTop + $(target).height();
        if(secTop <= position && secBottom >= position){
            elMenu.removeClass('active');
            elMenu.eq(i).addClass('active');
        }
    }
});

ウインドウサイズを変更したときにコンテンツの高さが変わることも考慮して、load、scrollの他にresizeでも発火させるようにします。

2~3行目でカレントが切り替わるタイミングを設定します。今回はウインドウの真ん中までコンテンツが表示されたらメニューのカレントが切り替わってほしいので、スクロールした距離にウインドウの半分の高さを足したものを現在位置とします。

先ほど取得した配列を使用して、5~7行目でコンテンツの上端と下端の位置をそれぞれ算出します。

あとはif文を使って現在位置が入っているコンテンツに対応するメニューにactiveクラスを付ければ、スクロールに応じてエレベーターメニューの色が変わるようになります。

最後にコンテンツ以外の部分ではエレベーターメニューは変化させないようにしたいため、「対象外」の部分を追記していきます。
先ほどの記述にプラスして、

$(window).on('load resize scroll', function(){
    const windowHeightHalf = $(window).height() / 2;
    const position = $(window).scrollTop() + windowHeightHalf;

    const firstContent = contentArr[0];
    const lastContent = contentArr[elMenu.length - 1];
    const outsideTop = $(firstContent).offset().top;
    const outsideBottom = $(lastContent).offset().top + $(lastContent).height();

    for(let i = 0; i < contentArr.length; i++){
        let target = contentArr[i];
        let secTop = $(target).offset().top;
        let secBottom = secTop + $(target).height();

        if(position < outsideTop || outsideBottom < position) {
            elMenu.removeClass('active');
        }

        if(secTop <= position && secBottom >= position){
            elMenu.removeClass('active');
            elMenu.eq(i).addClass('active');
        }
    }
});

5~8行目で最初のコンテンツの上端と最後のコンテンツの下端を定義します。

15~17行目で、最初のコンテンツより上もしくは最後のコンテンツより下だった場合は、activeを付けないというif文を追加すれば、コンテンツ以外でエレベーターメニューは点灯することはありません。

さいごに

今回はjQueryを使ってエレベーターメニューを実装しました。

エレベーターメニューを実装することで、前方一致や配列に格納した文字列の利用など、jQueryの理解が深まったので、これからの業務に活かしていきたいと思います。

この記事を書いた人

加藤 陵二
加藤 陵二ソリューション事業部 webデザイナー
アーティスへ入社後、webデザイナーとして大学サイトや病院サイト、企業サイト等のデザイン・コーディングに携わる。資格:Photoshopクリエイター能力認定試験スタンダード、illustratorクリエイター能力認定試験エキスパート、Webクリエイター能力認定試験初級
この記事のカテゴリ

FOLLOW US

最新の情報をお届けします