2
1

More than 3 years have passed since last update.

jQueryを使わずしてスムーススクロール

Last updated at Posted at 2020-08-31

はじめに

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

まとめ

jQueryを使わなくても意外と簡単に実装可能でした。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1