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

本文へ

フッターへ

お役立ち情報Blog



【jQuery】スクロール位置に応じて複数のコンテンツで背景を変化させる方法

最近、スクロール位置に応じてコンテンツごとに背景を変更する提案があり、実装してみたところ多くの学びがありました。
ユーザのアクションによって背景が変化するので、大きなユーザ体験を与えられるとともに、コンテンツに関してもとてもドラマチックに見せることが出来ます。

そこで今回はjQueryを使った、スクロールに応じてコンテンツごとに背景を変化させるテクニックをご紹介いたします。

1つのコンテンツに対して背景を変化させる

まずひとつ目のステップとして、1つのコンテンツに対してコンテンツが表示されたら背景色を変化させることを目的とします。
背景色の変化はコンテンツの擬似要素を透明から不透明にすることで表現します。 その際にトリガーとなるクラス show の追加・削除をjQueryで操作する流れになります。

HTMLとCSSの記述

ではHTMLとCSSの記述を見ていきましょう。

<div class="content__wrap">
    <p>背景なし背景なし背景なし背景なし背景なし背景なし</p>
</div>
<div class="content__wrap content-wrap--bg content-wrap--bg001">
    <p>赤色背景赤色背景赤色背景赤色背景赤色背景赤色背景</p>
</div>
.content__wrap {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 100vh;
}
.content__wrap p {
    padding: 50px;
    position: relative;
    z-index: 20;
}
.content-wrap--bg p {
    color: #fff;
}
.content-wrap--bg::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-position: center center;
    background-size: cover;
    background-repeat: no-repeat;
    opacity: 0;
    transition: all 0.5s ease 0s;
    z-index: 0;
}
.content-wrap--bg.show::before {
    opacity: 1;
}
.content-wrap--bg001::before {
    background: #7b0000;
}

HTMLの記述はシンプルで、背景なしのコンテンツと、背景を付けたいコンテンツのふたつのみです。
背景を付けたいコンテンツには content-wrap–bg クラスを付けました。
CSSで分かりやすいようにコンテンツの高さを100vhにしていたり、背景を付ける要素のフォントカラーを白にしていますが、重要なのは以下の3点になります。

  • コンテンツの z-index を背景用の擬似要素よりも高く設定すること
  • 背景用の擬似要素を position:fixed; にして画面いっぱいにすること
  • 背景用の擬似要素の opacity を通常では0に、 show クラスが付与されたときに1にすること

ここまでできたら、あとはjQueryで show クラスの操作を設定すれば背景が付くようになります。

jQueryの記述

続いてjQueryの記述をしていきます。 その前に、jQueryにおいて「指定のコンテンツが画面上に表示された」という判断をどのようにさせるかについて説明します。
使用するのは下記3つのメソッドです。

  •  height() :要素の高さを取得する
  •  scrollTop() :要素のスクロール位置を取得する(要素の上端が基準となる)
  •  offset() :要素の位置を取得する(offset().topで要素のY方向の位置を取得)

これらを使って、ウィンドウ高さ、ウインドウのスクロール位置、ページトップからコンテンツまでの位置を取得します。
スクロール位置とウインドウ高さの和がコンテンツの位置よりも大きくなった場合、「指定のコンテンツが画面上に表示された」と判断できます。

ただしこれでは1pxでも画面上にコンテンツが表示されたら背景がでてきてしまい、少し早すぎる気がするので、今回は画面上にコンテンツが表示されて画面の真ん中まで進んだ時とします。
つまり、「スクロール位置とウインドウ高さの和」が「コンテンツの位置とウインドウ高さの半分の和」より大きくなった時に背景を表示します。

以上のことを踏まえてjQueryを記述すると下記のようになります。

$(function(){
    const content = ".content-wrap--bg";
    const showClass = "show"; 

    $(window).on("load scroll resize", function(){
      const windowHeight = $(window).height();
      const scroll = $(window).scrollTop();
      const offset = $(content).offset().top;
      const setTiming = windowHeight * 0.5;

      if (scroll + windowHeight >= offset + setTiming){
        $(content).addClass(showClass);
      } else {
        $(content).removeClass(showClass);
      }
    });
});

スクロールしてから更新した際や、ウインドウの高さを変える場合に備えて、 scroll だけではなく load  resize でもイベントを発火させるようにしています。

表示結果は下記のようになります。

ちゃんと背景がついていることが分かりますね。

複数のコンテンツで背景を変更する

次に背景を変えたいコンテンツが複数ある場合について見ていきます。
HTMLとCSSは下記の記述を追加するのみになります。

<div class="content__wrap content-wrap--bg content-wrap--bg002">
    <p>青色背景青色背景青色背景青色背景青色背景青色背景</p>
</div>
<div class="content__wrap content-wrap--bg content-wrap--bg003">
    <p>黄色背景黄色背景黄色背景黄色背景黄色背景黄色背景</p>
</div>
.content-wrap--bg002::before {
    background: #00147b;
}
.content-wrap--bg003::before {
    background: #957e00;
}

この状態でスクロールしてみると、最初の背景を表示したいタイミングで show クラスが3つのコンテンツに同時についてしまい、結果として最後の背景が表示されてしまします。
各コンテンツでそれぞれ背景を出すには、先ほどのjQueryを各コンテンツごと繰り返し実行する必要があります。
方法はいくつかありますが、今回は each() メソッドを用いて記述します。

$(function(){
    const showClass = "show"; 

    $(".content-wrap--bg").each(function(index, content){
        $(window).on("load scroll resize", function(){
            const windowHeight = $(window).height();
            const scroll = $(window).scrollTop();
            const offset = $(content).offset().top;
            const setTiming = windowHeight * 0.5;

            if (scroll + windowHeight >= offset + setTiming){
            $(content).addClass(showClass);
            } else {
            $(content).removeClass(showClass);
            }
        });
    });
});

eachメソッドで content-wrap–bg クラスのついている要素に対して、繰り返し処理を実行します。

表示結果は下記のようになります。

それぞれのコンテンツで背景が出るようになりました。

背景を出す範囲を設定する

ここで一つ問題が出てきます。
それぞれのコンテンツにおいて条件を満たし背景を出したものの、その背景がずっと出てしまうという点です。

たいていのwebサイトにはフッターがありますので、フッターまで最後の背景が表示されているわけにはいきません。
それぞれのコンテンツに対し、背景を出している範囲を設定してあげれば解決しそうです。

$(function(){
    const showClass = "show"; 

    $(".content-wrap--bg").each(function(index, content){
        $(window).on("load scroll resize", function(){
            const windowHeight = $(window).height();
            const scroll = $(window).scrollTop();
            const offset = $(content).offset().top;
            const setTiming = windowHeight * 0.5;
            const contentHeight = $(content).height();
            const outTiming = windowHeight * 0.6;

            if (scroll + windowHeight >= offset + setTiming && scroll + windowHeight < offset + contentHeight + outTiming){
            $(content).addClass(showClass);
            } else {
            $(content).removeClass(showClass);
            }
        });
    });
});

コンテンツの高さを新たに取得し、コンテンツを通り過ぎてウインドウの高さの半分から少し過ぎたところを背景解除のタイミングとしました。
コンテンツの間にマージンなどがない限り、次のコンテンツの背景が出た後に前のコンテンツの背景が消えるので、継ぎ目なく背景が切り替わるはずです。
また、最後のコンテンツを過ぎれば背景は消えるので、フッターなど通常の背景を見せたい場合も問題はなくなります。

さいごに

いかがでしたでしょうか。
スクロールに応じて背景が変化すると、非常に動きのあるサイトという印象が与えられます。

今回は単純に背景色でしたが、背景を写真にすることでコンテンツのインパクトもより大きくなるでしょう。
また、これを応用すればスクロールに応じでアニメーションでコンテンツを出現させるといったことも出来ると思います。

やりすぎるとうるさくなりますので、ここぞというところに実装してみてはいかがでしょうか。

この記事を書いた人

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

FOLLOW US

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