ページ内リンク先のポジションの取得 (jQuery ver.)

前回のCSS版に続き今度はjQueryやJavaScriptでスムーススクロールを作っていきたいと思います。
必要なことを少しずつやっていって理解を深めたいので、今回はページ内リンク先の位置の取得についてのコードを書きます。

■ 今回のコード

CodePenで開く

重要なところを抜粋

$('a[href^="#"]').on('click', function () {
 const href = $(this).attr('href');
 const targetPos = href === '#' ? 0 : $(href).offset().top;
});

クリックをしたときに何をするかをjQueryを使い書く

まずはページ内リンクを意味する「#」から始まるhref属性を持つa要素をクリックしたときに何かをするという状態にします。

$('a[href^="#"]').on('click', function () {
 // クリックしたときに実行する処理を書く
});

ここでは.on('click')を使っています。代わりに.click()を使っても問題なさそうですが、普段から.on()を使う癖をつけていたほうが後々機能を追加したいときやより複雑なことをさせたいときに楽なので、これから先は.on()を使っていきます。
参考記事: jQuery 便利なonを使おう(on click) - Qiita

リンク先のポジションを取得

本題のクリックしたときの処理ですが、最初にhref属性の中身を定数「href」に代入します。

const href = $(this).attr('href');

そして定義した「href」を使い、リンク先がページトップからの何pxのところにあるのかを数値で取得し、定数「targetPos」に入れます。

const targetPos = $(href).offset().top;

.offset()の説明
.offset()は指定された要素がウェブページの中でどの位置にあるかを取得します。.offset().topで上からの位置を、.offset().leftで左からの位置を取得できます。
.offset()のみを使うとオブジェクトとして上と左の2つの値を同時に取得できます。
例: {top: 221.6875, left: 241.5}

■ href属性が「#」のみの場合をクリックした場合の処理

これでクリックしたときのリンク先の位置を取得できるはずですが1つだけ例外があります。ページトップへ飛ぶためにhref属性が「#」のみだった場合です。この場合値が取得できず上手く動きません。
なのでその場合のみこちらで数値に0を入れるようにします。

const targetPos = href === '#' ? 0 : $(href).offset().top;

hrefの中身が「#」ならば「0」を、それ以外ならば要素の位置を数値で取得して「targetPos」に入れます。

これで位置の取得ができました。

番外: ページトップへの移動位置をずらしたい場合
クリックしたときにページトップへ移動させたいけどきっちり0pxではなくヘッダー分を除いたトップから30px下に移動したいという機能を持たせたい場合も「#」だった場合の数字を変えることによって実現できます。「pageTopPos = 30」など事前に定義しておくと書き換えも楽かもしれません。

その場合の例はこちら

$(function () {
 const pageTopPos = 30;
 $('a[href^="#"]').on('click', function () {
   const href = $(this).attr('href');
   const targetPos = href === '#' ? pageTopPos : $(href).offset().top;
 });
});

■ 関連リファレンス

今回参考にしたページです。
js STUDIO jQuery 1.9 日本語リファレンスサイトより
.on() | jQuery 1.9 日本語リファレンス
.click() | jQuery 1.9 日本語リファレンス
.attr() | jQuery 1.9 日本語リファレンス
.offset() | jQuery 1.9 日本語リファレンス

■ CodePenに記載したコード

HTML

<h1>リンク先のポジションの取得</h1>

<section id="sec_toc">
 <h2>目次</h2>
 <ol>
   <li><a href="#sec_main-img">大きな画像があります</a></li>
   <li><a href="#sec_main-text">長い文章があります</a></li>
 </ol>
</section>

<section id="sec_main-img">
 <h3>大きな画像があります</h3>
 <img class="main-img" src="https://images.unsplash.com/photo-1587317822486-9ab2de18fa23?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ" alt="">
 <p>
   <a href="#sec_toc">目次に戻る</a>
 </p>
</section>

<section id="sec_main-text">
 <h3>長い文章があります</h3>
 <p>無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。無駄に長い文章。他</p>
 <p>
   <a href="#sec_toc">目次に戻る</a>
 </p>
</section>

<div class="totop">
 <a href="#">ページトップへ</a>
</div>

CSS

/* Reset */

html {
 line-height: 1;
 box-sizing: border-box;
}

*, ::before, ::after {
 box-sizing: inherit;
}

h1, ol, ul, p {
 line-height: 1.75;
}

img {
 vertical-align: top;
}

/* Style */

body {
 max-width: 960px;
 margin: 0 auto 44px;
 padding: 10px;
}

section {
 overflow: hidden; /* h2,h3などのmarginを貫通させないため */
}

.main-img {
 width: 100%;
}

.totop {
 position: fixed;
 bottom: 44px;
 right: 0;
 background-color: rgba(255,255,255,.8);
 padding: 10px;
}

JavaScript

'use strict';

$(function () {
 /* # から始まるa要素をクリックしたときに */
 $('a[href^="#"]').on('click', function () {
   /* href属性を取得 */
   const href = $(this).attr('href');
   /* 要素の位置を取得 */
   const targetPos = href === '#' ? 0 : $(href).offset().top;
   alert('リンク先の位置はページトップから\n「' + targetPos + 'px」の場所にあります。');
 });
});


この記事が気に入ったらサポートをしてみませんか?