脱初心者備忘録

スクロールに応じて表示される、ページトップに戻るボタンの実装

ページを下まで読んでいると、上に戻りたくなるときありますよね。
そんなとき、クリックするだけで戻ると非常に便利。
だけど、スクロールするほど、コンテンツ量が無いときにも表示されていると無駄な気がする。
そんな時に便利なページトップボタンを、jQueryで実装します。

基本のHTMLの記述

まずコンテンツを記述したHTMLを用意し、戻るボタンを記述します。
ボタンは、FontAwesome で表示するので、<head>から</head>の間に、FontAwesome のCSSをCDNで読み込みます。

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />

ボタンの位置はお好みでOKなんですが、今回のサンプルは、フッターから10px上で、右端から50pxの位置に表示するよう記載しました。
また、ボタンはちょっとだけ透過を入れ、マウスオーバーで、色が濃くなるように記述しました。

//戻るボタンを実装したHTML
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ページトップにスクロールするボタン</title>


   <!-- Fontawesome のCDNを読み込む  ここから-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />

  <!-- Fontawesome のCDNを読み込む ここまで -->

    <link rel="stylesheet" href="scroll.css">
</head>

<body>
    <div id="page">
        <header>ヘッダー</header>
        <div id="wrapper">
            <main>メインコンテンツ</main>
            <div id="pagetop">
                <a href="#"><i class="fas fa-arrow-alt-circle-up fa-3x" title="to Top"></i></a>
            </div>
        </div>
        <footer>フッター</footer>
    </div>
</body>

</html>
//上記の<head>で読み込んでいるscroll.css の記述
@charset "utf-8";
body,
html {
    margin: 0;
    padding: 0;
}

#page {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    justify-content: center;
}

header {
    background-color: #eee;
    border-bottom: 5px solid #555;
    height: 100px;
    text-align: center;
    padding: 1rem;
    box-sizing: border-box;
}

#wrapper {
    flex: 1;
    text-align: center;
    padding: 1rem;
    box-sizing: border-box;
}

footer {
    margin-top: auto;
    background-color: #ccc;
    border-top: 5px solid #555;
    height: 100px;
    text-align: center;
    padding: 1rem;
    box-sizing: border-box;
}

#pagetop {
    font-size: medium;
    position: fixed;
    right: 50px;
    bottom: 110px;
}

#pagetop a {
    color: rgba(85, 85, 85, 0.6);
}

#pagetop a:hover {
    color: rgba(85, 85, 85, 1);
}

現在のHTMLの表示はこうなります。


ボタンは、〇に上向きの矢印で表示しています。
お好みのものに変えるには、FontAwesomeのサイトでアイコン検索してコードを変更してください。

classの中身を検索結果のアイコンから、コピー&ペーストして書き換えるだけです。

FontAwesome

<i class="fas fa-arrow-alt-circle-up fa-3x" title="to Top"></i>

jQuery 本体をCDNで呼び出す

次にスクロール動作に必要なjQuery本体を、CDNでHTMLの中に読みこみます。
HTMLのヘッダーもしくはbodyタグの閉じタグの直前に記述します。

<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
</body>
</html>

お約束として、自分の作ったjQueryのプログラムよりも前にjQuery本体を置くこと。
そうしないと、「jQueryがないよー」っていうエラーが出て動作しない。

スクロールに関してのプログラムをjQueryで記述する

今、何もしてないので、pagetopボタンが、表示されたままです。
これを、ブラウザのウィンドウが400ピクセルよりスクロールされたら、ふわっとボタンが表示する といったコードにしてみたいと思います。

//ブラウザウィンドウを500px縦にスクロールしたらボタン表示
$(function() {
    var topBtn = $("#pagetop"); //idがpagetopのボタンの定義
    topBtn.hide(); //ページが読み込まれた段階では、ボタンは表示しない

    $(window).scroll(function() {  //ブラウザをスクロールしたら
        if ($(this).scrollTop() > 400) { //スクロールの距離が500pxより大きければ
            topBtn.fadeIn();  //ゆっくり表示
        } else {
            topBtn.fadeOut();  //ゆっくり消す
        }

    });

});

ボタンは消えます。

ただ、現在コンテンツがなく、スクロールできないので、ここで、HTMLのmainタグにコンテンツを追加します。高さのある画像を入れてみました。

 

スクロールして下に行くと、ふわっと表示されました。

ページ内リンクをしたいので、コードを記述する

ページ内リンクは、a要素に#かidを書いて、目的の場所にジャンプすることを言います。
長い記述のコンテンツではよく使われます。このブログでも目次で利用したりしてます。

ただ、このページ内リンクは、URLの最後に#とか#topなどのパラメータがついてしまいます。

通常のHTMLであれば、問題なく動作するページ内リンクですが、PHPで構成されたHTMLの場合、URLに#がついているだけで、同一ページリンクとはみなされず、挙動がおかしくなる場合があります。

なので、jQueryでクリックされたリンク先を判別し、同一ページ内リンクであれば、#をURLから削除してから、目的の場所に移動するといったコードを記述します。

//リンク先の判別
$(function() {
    //hrefが#から始まるurlのa要素がクリックされたら
  $('a[href^="#"]').click(function() { 

        var time = 500;
        var href = $(this).attr("href"); //hrefの中身を取得
        var target = $(href == "#" ? 'html' : href); //hrefが#だけならhtml
        var distance = target.offset().top; //特定の要素が配置されている座標

        $("html, body").animate({
            scrollTop: distance
        }, time, "swing"); //htmlはdistanceをtimeの時間をかけて移動する

        return false; //ページ遷移しない

    });  
});

これでいったん、pagetopボタンをクリックしてみます。

ちゃんとページ上部に移動しましたが、URLの末尾に#はありません。すっきりです。

ページ内リンクの確認をする

先ほどは、ページトップボタンの動作確認でしたが、ページ内リンクの確認も必要なのでここで行います。

まずテスト用に、HTMLにコンテンツを増やします。

a要素に書かれている内容は以下の通り
<a href="#page_middle">ページ下のほうに移動したいよ</a>
これをクリックして、リンク先(「ページ下のほう」という文字)に移動し、さらにURLに#page_middleが無ければ完成です。

WordPressで使う場合

WordPressでは、jQueryをそのまま書くと、$ is not define.. なエラーが出て動作しません。
jQueryをそもそも読み込んでない場合は、まず読み込んでください。ってことですが、Wordpressにはお作法があって、あるコードを書かないとうまくjQueryが動作しません。

jQueryを動作させたい部分に以下のコードを1回書いてください。
これは「$関数の動作が先に定義されている動作に戻る。」という意味です。

var $ = jQuery.noConflict();

このコードを書いてから、普通にjQueryのコードを書くと動作するはずです。

Laravelで使う場合

Laravelではまず、jQueryを使えるようにしてあげる必要があるので、webpack.mix.js にコードを追加します。

スクロールを動作させるjQueryのコードは別ファイルに記述し保存します。
保存場所は、resources の中に js フォルダを作り、その中に scroll.js として保存します。

webpack.mix.js には、scroll.js とjQueryの2つの記述を行います。

//webpack.mix.js
mix.js('resources/js/app.js', 'public/js')
    .js('resources/js/scroll.js', 'public/js')
    .autoload({
        'jquery':['$', 'window.jQuery'],
    })
    .postCss('resources/css/app.css', 'public/css', [
      require('postcss-import'),
      require('tailwindcss'),
      require('autoprefixer'),
]);
//scroll.js ( resources\js\scroll.js )
$(function () {
  var topBtn = $("#pagetop");
  topBtn.hide();

  $(window).scroll(function () {
    if ($(this).scrollTop() > 400) {
      topBtn.fadeIn();
    } else {
      topBtn.fadeOut();
    }
  });

  $('a[href^="#"]').click(function () {
    var time = 500;
    var href = $(this).attr("href");
    var target = $(href == "#" ? 'html' : href);
    var distance = target.offset().top;
    $("html, body").animate({
      scrollTop: distance
    }, time, "swing");
    return false;
  });
});

コードを追加後、laravel mixを再ビルドするため、npm run dev します。

//コマンド実行
npm run dev

ビルド後は、自動でbodyタグの閉じタグ上部に読み込まれます。