スクロールで要素を横からフェードインさせてみよう

css

先日、CSSでTransitionを利用したアニメーションの記事を書きましたが、それを利用して、よく他社のサイトで見るスクロールしたら文字などが下や横からフェードインしてくるコンテンツありますよね?せっかくなので、作ってみようかと思います。

全体の流れとサンプル

全体の流れやポイント、サンプルも先に乗せておきます。今回は、jQueryも使用していきます。

  • フェードインさせる要素はあらかじめ非表示にしておき位置を左側にずらしておく
  • スクロール量の値が特定の値まで達したらjQueryでクラスを付与する
  • クラス付与するとアニメーションが実行される

ソースコード

ソースコードに関しては不要な部分はそぎ落としていきます。実際のコードはサンプルのCodepenで確認してください。

 

フェードインさせるコンテンツ

フェードインさせるコンテンツ

フェードインさせるコンテンツ

フェードインさせるコンテンツ

/* フェードインするボックスの設定 */
.box{
  width:50%;
  margin:50% 5% 5% 5%;
  text-align:center;
  background-color:#ffff00;
  padding:5%;
  border:1px solid #333;
  transform:translateX(-50px); /* 最初は元の位置より左にずらしておく */
  opacity:0;  /* 最初は非表示にしておく */
  transition:opacity 1s,transform 0.5s; /* 透明度と位置を設定 */
}

/* 条件を満たしたあとに追加するクラス */
.fadein{
  opacity:1; /* 表示させる */
  transform:translateX(0); /* 位置を最初の位置に戻す */
}
//ウィンドウの高さを取得する
var window_h = $(window).height();

//スクロールイベント
$(window).on("scroll", function() {
  
  //スクロールの位置を取得する
  var scroll_top = $(window).scrollTop();
 
  $(".box").each(function() {
    //各box要素のtopの位置を取得する
    var elem_pos = $(this).offset().top;
    
    //どのタイミングでフェードインさせるか
    if (scroll_top >= elem_pos - window_h + 300) {
      $(this).addClass("fadein"); //特定の位置を超えたらクラスを追加
    } else {
      $(this).removeClass("fadein"); //そうでない場合はクラスを削除
    }
  });
});

サンプル

上記のコードを実際に再現したサンプルが下記です。
スクロールすると要素が右からフェードインしてきます。

See the Pen transitionを利用してスクロールで要素を横からfadeInさせてみよう by 石切山 公宏 (@kirikirimai) on CodePen.

各ソースコードの解説

HTML

htmlは、見ていただければ分かるかと思います、フェードインさせる「box」というクラスのdiv要素があります。

CSS

そしてこのbox要素を予め、「opacity」プロパティで0にして非表示にしておき、「transform」プロパティの「translateX」でx軸(横)方向に「-50px」左側にずらしておきます
*ちなみに要素を移動させる際に、絶対配置にして「left」「top」のプロパティで動かすこともありますが、このやり方だとPCに負担を与えてしまい、 アニメーションがカクカクになる原因になることもあります。状況によって使い分けましょう。

あとは「fadein」クラスの設定で「opacity」と「translateX」で表示と右側にアニメーションさせる設定にしておきます。
後々、jQueryでこのクラスを追加する事でTransitionアニメーションが実行されます。

jQuery

必要な値は、読み込み時のウィンドウの高さスクロール量各ボックスの要素のトップの位置が必要となります。
スクロール量は、windowオブジェクトにscrollイベントで取得し、各ボックス要素のトップの位置に関してはスクロール内でeach処理内で取得する 。

ちなみに各ボックス要素の位置をoffsetで取得しますが、ブラウザの左上ではなく、ドキュメントの左上となります。 ですので、スクロールしたら起点はブラウザ上からは見えなくなります。
*ドキュメントとはHTML要素を構成するdocumentオブジェクトだと思ってください。

//ウィンドウの高さを取得
var window_h = $(window).height();

//スクロールイベント
$(window).on("scroll", function() {
  //スクロール量を取得
 $(window).scrollTop()
 
 //eachにより各ボックスの処理
  $(".box").each(function() {
  //各ボックスのトップの位置
    var elem_pos = $(this).offset().top;

  });
})

どのタイミングでフェードインさせるか?

必要な値を取得したら、ウィンドウのどの位置でフェードインさせるかを決めなければいけません。考え方としては、スクロール量の値がその特定の値を上回った場合にtrue そうでなければfalseという真理値による条件分岐でアニメーションさせる為のクラスを追加・削除するという流れです。  まずは下記の画像を見てください。

参考として、「ウィンドウの高さを500px」「 ボックス要素 のtop位置を530px」としておきます。スクロール量が0の時は、ちょうどボックス要素はウィンドウの高さの30pxほど下の位置にいて隠れている状態です。そして 「スクロール量が30px」を超えた した場合にどうなるか?説明していきます。

このボックス要素がウィンドウの内、、つまりウィンドウの高さの「500px」以内に入ればいいのですが、ボックス要素のtopの位置はドキュメント(documentオブジェクト)の上からの位置になるのでスクロールしたところでドキュメント全体がスクロールされてるのでボックス要素のtopの位置は変わりません。

ではボックス要素がウィンドウ画面内に入ったか?を検知すればいいのか、、、スクロールするとドキュメントは上にスクロールされていきますよね?
つまり「ボックス要素のtop位置」から「ウィンドウの高さ」を引いた差分の値と実際のスクロール量の値を照らし合わせればいいのです。

画像の例でいえば「530 – 500」となり差分の値は30となります。この差分の値とスクロール量の値を比較してスクロール量が30を上回った時にボックス要素はウィンドウ内に入ったと判定できます。
そして差分の値とスクロール量の値がイコールの時は、ボックス要素はウィンドウの高さと同じ位置にいるという事になります。
これを下記の式を表すことができます。

if(scroll_top >= elem_pos - window_h){
   //trueになるので、fade_inクラスを追加
} else{
   //falseになるので、fade_inクラスを削除
}

これでもいいのですが、この条件式だとボックス要素がウィンドウ内に入った瞬間にアニメーションが実行されることになります。
出来ればもう少しボックス要素がウィンドウ画面の中に入った状態や真ん中付近でアニメーションを実行させたいですよね。
そのためには値を調整する必要があるので、この条件式に「+200」あたりを足してあげるといいでしょう。この値は実際に確認しながら微調整するといいです。

if(scroll_top >= elem_pos - window_h+200){
   //trueになるので、fade_inクラスを追加
} else{
   //falseになるので、fade_inクラスを削除
}

調整する値「200」を足すことによって、スクロール量の値が「30」以上でも差分の値が「230」となるので、if文の条件が成立しないので、アニメーションは実行されずスクロール量が「230」以上の時にif文の条件が成立します。この時、ボックス要素はスクロールされることにより、上に移動するので、ウィンドウの高さを基準とすると「500 – 200」の「300」の位置に表示されている事になります。こうすれば、ボックス要素がウィンドウの高さの中に入った状態で「fade_in」クラスを追加され、transitionアニメーションが実行されることになります。

複数の要素ごとに条件判定するには?

アニメーションが実行されるまでのロジックは上記で説明しましたが、ボックス要素が複数ある場合は、それぞれのボックス要素のtop位置の値と比較しないといけません。
そこで、each文を使ったすべてのボックスのtop位置の値と差分の値を比較して条件式を成立させる必要があります。

$(".box").each(function() {
  
    //それぞれののボックス要素の位置を取得する
    var elem_pos = $(this).offset().top;

    //どのタイミングでフェードインさせるか条件式
    if (scroll_top >= elem_pos - window_h+200) {
      $(this).addClass("fadein"); //fadeinクラスを追加
    } else {
      $(this).removeClass("fadein"); //fadinクラスを削除
    }
  });

これで各ボックス要素と比較ができます。

まとめ

今回、説明が長くなりましたが、ロジックさえ理解すれば難しくはないかと思います。どこかのライブラリを使うのもいいですが、ロジックが理解していないとカスタマイズも難しかったりしますので、知っておけばいろいろ対応できますね。