##はじめに
jQueryを使わずにスムーススクロールを実装してみました。
##コード
さっそくコードを記載します。
const links = document.querySelectorAll('a[href^="#"]');
links.forEach((link) => {
link.addEventListener('click', (e) => {
e.preventDefault();
const linkId = link.getAttribute('href');
const linkDom = document.querySelector(linkId);
const linkPosition = linkDom.getBoundingClientRect().top;
const currentPosition = window.pageYOffset;
const position = linkPosition + currentPosition;
window.scroll({
top: position,
behavior: 'smooth',
});
});
});
##簡単に解説
まず、href属性値のうち、「#」に前方一致するa要素群を取得します。
const links = document.querySelectorAll('a[href^="#"]');
それぞれのa要素に対してクリックイベントリスナーを登録します。
links.forEach((link) => {
link.addEventListener('click', (e) => {
// 処理
});
});
preventDefault()メソッドは、既定のイベントをキャンセルします。
これによって、リンクをクリックした際に、瞬時にリンク先へ移動するのを防いでくれます。
e.preventDefault();
a要素のhref属性値を取得し(linkId)、その属性値をidに持つ要素を取得します(linkDom)。 これを基に、画面の表示領域の左上を0とした時のlinkDomのy座標を取得します(linkPosition)。 また、現在のスクロール位置のy座標を取得します(currentPosition)。
linkPositionとcurrentPositionを足し合わせると、リンク先のy座標の絶対値となります(position)。
const linkId = link.getAttribute('href');
const linkDom = document.querySelector(linkId);
const linkPosition = linkDom.getBoundingClientRect().top;
const currentPosition = window.pageYOffset;
const position = linkPosition + currentPosition;
最後に、window.scrollを使ってスクロールさせます。 topには絶対位置を指定する必要があるので、上記の処理(positionの算出)が必要です。 そして、オプションのbehaviorを'smooth'に指定することでスムーススクロールが実現します。
window.scroll({
top: position,
behavior: 'smooth',
});
##おまけ
ついでに、クラスを使って表現し直してみました。
main.js
class SmoothScroll {
constructor() {
this.DOM = {};
this.DOM.links = document.querySelectorAll('a[href^="#"]');
this._init();
}
_init() {
this.DOM.links.forEach((link) => {
link.addEventListener('click', (e) => {
e.preventDefault();
this._performScroll(link);
});
});
}
_performScroll(link) {
const linkId = link.getAttribute('href');
const linkDom = document.querySelector(linkId);
const linkPosition = linkDom.getBoundingClientRect().top;
const currentPosition = window.pageYOffset;
const position = linkPosition + currentPosition;
window.scroll({
top: position,
behavior: 'smooth',
});
}
}
const ss = new SmoothScroll();
HTML、CSSのサンプルも載せておきます。
index.html
<body>
<header class="header">
<ul class="header-items">
<li class="header-item"><a href="#title1">Title1</a></li>
<li class="header-item"><a href="#title2">Title2</a></li>
<li class="header-item"><a href="#title3">Title3</a></li>
<li class="header-item"><a href="#title4">Title4</a></li>
</ul>
</header>
<main>
<section class="section" id="title1">
<h2 class="title">Title1</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit,</p>
</section>
<section class="section" id="title2">
<h2 class="title">Title2</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit,</p>
</section>
<section class="section" id="title3">
<h2 class="title">Title3</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit,</p>
</section>
<section class="section" id="title4">
<h2 class="title">Title4</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit,</p>
</section>
</main>
<script src="main.js"></script>
</body>
style.css
html, body, h2, ul
{
margin: 0;
padding: 0;
border: 0;
}
ul {
list-style: none;
}
main {
margin-top: 70px;
}
.header {
position: fixed;
top: 0;
right: 0;
left: 0;
z-index: 20;
background-color: lightgray;
}
.header-items {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding: 0 40px;
}
.header-item {
margin: 0 auto;
}
.header-item > a {
text-decoration: none;
height: 70px;
line-height: 70px;
display: inline-block;
padding: 0 20px;
}
.title {
text-align: center;
}
.section {
padding: 40px;
text-align: center;
height: 100vh;
border: 1px solid #000;
background-color: lightcyan;
}
見た目はこんな感じ。 ![htmlExample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507401/2449118f-baf9-04d7-70f2-921e693c493c.png)
##まとめ
jQueryを使わなくても意外と簡単に実装可能でした。