「ページトップへ戻る」
webサイトでスクロールが深くなると上に戻るのが大変になります。そこでページ上部に戻るための機能を付けるサイトも多いです。
多くの場合は一定スクロールすると、クリックするとページ上部に戻れるアイコンなどを表示する方法です。
単純な機能だがユーザビリティが高まるし、相対的にスクロールが深くなりやすいスマートフォンサイトなどではぜひ設置したいものです。
今回の記事ではこの「ページトップへ戻る」機能をjQueryを用いて作りたいと思います。
要件の定義
「ページトップへ戻る」はその名の通りページトップにスクロールさせるという機能です。
今回ではある程度スクロールすると「ページトップへ戻る」アイコンが出現するようにしたいと思います。出現は透明度を使ってフェードインしてくるようにするつもりです。
また戻りスクロールは「スクロールした」ということを感じてもらう為、スクロール移動はアニメーションにて行いたいと思います。戻りスクロールを一瞬でする方法もありますが、あまりに一瞬だとユーザーに何が起こったのか混乱させる可能性もあります。
イメージとしては以下のような感じにしたいです。
スクロール量を取得する
.scrollTop()を使う
一定スクロールしてからアイコンを出すので、スクロール量を計測する必要があります。スクロール量を取得するのは、jQueryの.scrollTop()メソッドを使う。
通常画面全体のスクロール量はhtmlかbodyで取得します。
//スクロール量の取得
$( "html" ).scrollTop();
$( "body" ).scrollTop();
クロスブラウザ対応の必要性
単純にどちらかで取得できればいいのですが、めんどくさいことに、主要ブラウザで.scrollTop()の取得され方に差異があります。 chromeはhtmlでスクロール量を取得できず、IE,FireFoxはbodyで取得できないです。(これはブラウザのバージョンアップが進むと解消されるかもしれないので、常に確認は必要)
.scrollTop()を取得する場合はクロスブラウザ対応が必要になります。.scrollTop()のクロスブラウザ対応を考えてみましました。
$( window ).on( "scroll" , function(){
var scroll;
//判別の為とりあえず$( "body" ).scrollTop()で取得してみる
var scroll_distinction = $( "body" ).scrollTop();
//body要素でスクロールを取得できているか
//出来ていませんでしました。ら"html"出来ていたら"body"
if( scroll_distinction === 0 || scroll_distinction == false ){
scroll = $( "html" ).scrollTop();
}else{
scroll = $( "body" ).scrollTop();
};
});
windowに対してscrollが発生したときに実行されます。 実行された時点でhtmlかbodyにはスクロール量が発生していますので、仮にbodyで取得してみて値の状態を判断し、条件分岐させています。
分岐条件にscroll_distinction == falseがあるのは念の為0以外の値(undefinedやNaNやnull)になった場合を想定しています。(0でもflaseになるので条件はscroll_distinction == falseだけでもいいのかもしれない)
もっとうまいやり方があるかもしれないですが、@MINOにはこれが精いっぱいなので勘弁してほしいです。
スクロールしたら
「ページトップに戻る」を表示させるのは、画面一つ分の高さをスクロールしたら…という条件にしたいと思います。これは好みの問題なので、各位が好きなタイミングで構わないです。
画面の高さは以下で取得できます。
$( window ).height();
ページトップへ戻る
前述したようにページトップに戻るのはアニメーションを使いたいと思います。
アニメーションというと複雑なように感じるかもしれないですが、今回は動きが直線的で構わない上に、戻る場所を複雑に計算する必要もないです。以下の記述でページトップにスクロールできます。
$( "html,body" ).animate( { scrollTop: 0 } , "2000" );
これは現在のスクロール位置からhtmlもしくはbodyのスクロール0地点(通常であればページ一番上)にアニメーションするということです。第2引数の2000はアニメーションに要する時間をミリ秒で指定しています。ミリ秒は1/1000秒なので、2000で2秒となります。
実際にはクリックしたときに発動させたいので以下の記述になります。
$( "#pageTopIcon" ).on( "click" , function(){
$( "html,body" ).animate( { scrollTop: 0 } , "2000" );
});
クリックイベントにイベントハンドラとしてアタッチしています。これで「ページトップに戻る」アイコン(#pageTopIcon)をクリックする と2秒でページトップに戻る事になります。秒数はお好みだがあまり早すぎても遅すぎても良くはないと思います。
徐々に現れるアイコンを実現する
opacityの活用
徐々に現れる効果を出すためにcssプロパティのopacityを使用したいと思います。opacityは透明度を設定するプロパティです。opacity値の増減でアイコンの表示を制御します。
opacityの値
opacityの値は0.0から1.0までで、0.0が完全な透明、1.0が完全な不透明になります。ただし透明になったとしても要素が消えてなくなるわけではなく、見えないだけでその位置に居続けています。
「ページトップへ戻る」アイコンの表示位置を固定・調整する
positionプロパティ
「ページトップに戻る」アイコンはその機能の性格上、スクロールしてしまっては話になりません。その場にとどまらせる必要があります。その為cssプロパティpositionにてfixdeを設定し位置を固定します。
表示位置の調整
positionプロパティでfixdeを指定した場合、その要素は親要素を基準として表示されることになります。親要素左上隅の位置がデフォルトです。今回はbody直下にimgタグにてアイコンを設置しますが、このままでは具合が悪いので、位置を変える必要があります。
「ページトップへ戻る」アイコンは画面右下あたりに表示させたいです。これにはrightプロパティとbottomプロパティを使って位置を決めます。 これらのプロパティは右端からどのくらい、下からどのくらいの距離に表示させるという設定が出来ます。
「ページトップへ戻る」機能の実装
コード
これまでに説明した事を念頭にコーディングしてみましました。
//ページトップへ戻る機能
$( window ).on("scroll ready resize", function(){
var windowHeight = $( window ).height();
var scrollDistinction = $( "body" ).scrollTop();
//body要素でスクロールを取得できているか
var scroll;
//出来ていませんでしました。ら"html"出来ていたら"body"
if( scrollDistinction === 0 || scrollDistinction == false ){
scroll = $( "html" ).scrollTop();
}else{
scroll = $( "body" ).scrollTop();
};
//出現位置決定用係数(単位は画面の高さ)
var line = 1.8;
//出現が始まる位置
var changeFieldStartPoint = windowHeight;
//opacityが1.0になる位置
var changeFieldEndPoint = windowHeight * line;
//変化域
var changeField = changeFieldEndPoint - changeFieldStartPoint;
//opacityの値
var opacityAmount = ( scroll - changeFieldStartPoint ) / changeField ;
if( scroll < changeFieldStartPoint || scroll <= 0){
$( "#pageTopIcon" ).css( "opacity" , "0.0" );
}else if( scroll > changeFieldStartPoint && scroll < changeFieldEndPoint ){
$( "#pageTopIcon" ).css( "opacity" , opacityAmount );
}else if( scroll >= changeFieldEndPoint ){
$( "#pageTopIcon" ).css( "opacity" , "1.0" );
}
$( "#scrollAmount" ).text( "現在のscroll量 " + scroll + " px" );
$( "#changeFieldStartPoint" ).text( "スタートポイント " + changeFieldStartPoint + " px" );
$( "#changeFieldEndPoint" ).text( "opasity値が1.0に到達する場所 " + changeFieldEndPoint + " px" );
$( "#changeField" ).text( "変化域 " + changeField + " px" );
$( "#opacityAmount" ).text( "現在のopasity値 " + opacityAmount + " px" );
//クリックされたらアニメーションでサイトトップにスクロールする
$( "#pageTopIcon" ).on( "click" , function(){
$( "html,body" ).animate( { scrollTop: 0 } , "2000" );
});
});
このコードが動くデモページも作成しました。コードはすべてhead内に記述していますので、お使いのブラウザのF12を押してデベロッパーツールで確認していただけると幸いです。
また動作のイメージを追いやすいように画像も拵えたので合わせて参照することをお勧めします。
補足説明
変化域の考慮
今回の例ではページの高さに関わらず、設定した変化域でopacityが0.0~1.0に変化するようにしてあります。こうするとchangeFieldEndPointの位置でopacityが1.0になるので、透明度変化がスムーズにアニメーションしているかのように見えるかと思います。
もし変化域を考慮していないと、opacityAmountの変化量がページの高さによって変わってしまうのであまり良くない(と思う)。
例ではwindowHeightを「出現スタート位置」=changeFieldStartPointに、windowHeight*lineが「opacityが1.0になる位置」=changeFieldEndPointとして設定しています。lineという変数は画面の高さを何個分で基準とするかの係数につかっています。
changeFieldStartPointからchangeFieldEndPointを引くと、「ページトップに戻る」アイコンの透明度変化域=changeFieldを算出できるようにしています。
これで変化域を特定できるので、scrollからchangeFieldStartPointを引いた値をchangeFieldで割ることで、変化域でopacityAmountが0.0~1.0になるようにしています。
scrollを基準にしてopacityAmount値を作り出すことでスクロールが戻るときにもちゃんと透明度変化が行われるようにしています。
本来の機能とは関係のないところですが、どうせならきれいに動作してほしいと思っています。
その他
いくつか数値を表示させる為のコードが入っていますが、これは本来の機能と関係ないので無視していただいて構わないです。
まとめ
「ページトップに戻る」機能について、ちゃんとした名称があるのかどうか調べたがよくわからなかった。どうもまんま「ページトップに戻る」で呼ばれているようです。
今回はjQueyでCSSをいじるという簡単な例だったので理解していただきやすいのではないかと思います。@MINOがスムースな変化に変なこだわりを持たなければもっと簡潔なコードで済むはずです。むしろ「ページトップに戻る」アイコンがいきなり出現したってかまわないのだから。
余計な実装をすることで未だに9割方無職なのではないかと疑わなくもないです。
@MINOも「ページトップに戻る」で一番よかったあの頃へ戻りたいです。