縦長のページではアニメーションが伴っているものがよくありますが、スクロールによって要素がウィンドウ内に入ったかを検知して処理を実行する、といったものをjQueryでプラグインを使用せず作成します。
レスポンシブデザインで組んでいて要素の座標がウィンドウ幅によって変わるって場合でも大丈夫です。
今回は画像がウィンドウ内に入ったらopacityの値を1に、外に出たら0になるものを作成します。
html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<div id="wrapper"> <h1>ウィンドウに入ったか検知するデモ</h1> <section> <div class="container"> <h2>1つ目の画像</h2> <img src="./images/image_1.jpg" alt="1つ目の画像" /> </div> <div class="container"> <h2>2つ目の画像</h2> <img src="./images/image_2.jpg" alt="2つ目の画像" /> </div> <div class="container"> <h2>3つ目の画像</h2> <img src="./images/image_3.jpg" alt="3つ目の画像" /> </div> <div class="container"> <h2>4つ目の画像</h2> <img src="./images/image_4.jpg" alt="4つ目の画像" /> </div> <div class="container"> <h2>5つ目の画像</h2> <img src="./images/image_5.jpg" alt="5つ目の画像" /> </div> </section> </div> |
css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
html, body { width: 100%; font-size: 16px; } #wrapper { box-sizing: border-box; width: 100%; max-width: 600px; margin: 0 auto; padding: 0 8px; } h1 { font-size: 1.6em; margin-bottom: 20px; } .container:not(:last-child) { margin-bottom: 600px; } h2 { font-size: 1.4em; } img { width: 100%; height: auto; } |
jQuery
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$(document).ready(function(){ $("img").css({ "opacity": "0" }); $(window).on("load",elemChange); $(window).on("scroll",elemChange); $(window).on("resize",elemChange); $(window).on("touchmove",elemChange); function elemChange(){ $("img").each(function(i){ var windowTop =$(window).scrollTop(); var windowBottom = windowTop + $(window).height(); var elemTop = $(this).offset().top; var elemBottom = elemTop + $(this).height(); if(((elemTop <= windowBottom && elemTop >= windowTop) || (elemBottom >= windowTop && elemBottom <= windowBottom) || (elemTop <= windowTop && elemBottom >= windowBottom)) && !($(this).hasClass("show"))){ $(this).removeClass("hide").addClass("show"); $(this).stop().animate({ "opacity": "1", }, 1500); }else if((windowBottom < elemTop || windowTop > elemBottom) && !$(this).hasClass("hide")){ $(this).removeClass("show").addClass("hide"); $(this).stop().animate({ "opacity": "0", }, 1500); } }); } }); |
少し長くなりますがelemChangeの説明です。
まずスクロール値をウィンドウの上部、それにウィンドウの高さを足したものをウィンドウの下部としてそれぞれ変数を用意します。またoffset()メソッドを使用して、要素の上部、それに要素の高さを足したものを要素の下部として変数を用意します。
if文の条件ですが、少し長くなってしまいました。ざっくり言うと対象要素の上部か下部がウィンドウの上部から下部の間に入った場合、さらに要素がウィンドウの高さをはみ出してしまう場合を考慮して要素の上部がウィンドウの上部より上であり、要素の下部がウィンドウの下部より下にある場合、となっています。
.each()メソッドを使い、対象要素全てに条件分岐で分けて処理を与えましょう。
条件内の.hasClass()及び処理内.addClass()、.removeClass()はウィンドウ内云々とはすこし話がそれるのですが、クラスの削除、付与でウィンドウ内の要素であるか否かを分けています。
この関数をscrollイベントに紐付け、他に画面サイズが変わり要素がウィンドウ内に入った時にresize、スマホを考慮してtouchmove、ページを読み込んだ時のloadの各イベントにも紐付けます。
今回は省きましたが、要素を追加で読み込む等ページ全体の高さに影響を与える場合、そのタイミングで関数(今回の場合はelemChange)を実行する、といった形をとったほうがいい場合もあるかもしれません。
問題点は一部ブラウザ、例えばiOS版のGoogle Chlomeだとスクロールの慣性中は処理が実行できない場合があるという点。
あまり労せずに対処できるなら教えて下さい!
本題とはずれますが、アニメーションの処理で不都合を防ぐため少々長くなってしまいました。もしもっと簡潔に済むならこちらもおしえていただければ幸いです。
この記事をシェアする