ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

ページに目次をつけて、項目を押したらスクロールする

 ものすごい小さい話ですが、毎回忘れてしまうのでメモします。

$('html,body').animate({
  scrollTop: window.pageYOffset + target.getBoundingClientRect().top - 8 // 要素がブラウザ上部ぴったりになるので少し隙間をあけたり
}, 500, 'swing');

 まずwindow.pageYOffsetについて、これはwindow.scrollYエイリアスだそうです。ページの一番上を0として、どのくらい下にスクロールしているかのピクセル値を返します。

 次にelement.getBoundingClientRect().topですが、現在クライアントが見ている画面の上端を0として、そこからどれくらい要素が離れているかをピクセル値で返します。例えば要素をスクロールして通り過ぎていたら、負の値が返ってきます。

  つまり、ページの一番上から現在表示している画面上端までの距離現在表示している画面上端から要素までの距離を足すことでページの一番上から要素までの距離を計算しているということになります。(多分絵で描くとわかりやすい???)

ページの一番上から現在表示している画面上端までの距離

f:id:ushumpei:20170925210302p:plain

現在表示している画面上端から要素までの距離

f:id:ushumpei:20170925210314p:plain

まとめ

 多分覚えたのでもう忘れないはずです。ぶっちゃけていうとすでにここに書いてありました。。。

おまけ

 デモです。

See the Pen MEbNmj by ushumpei(@ushumpei) on CodePen.

一枚にまとめたやつ

<html>
  <head>
    <style type="text/css">
      .container {
        display: flex;
        flex-direction: row;
        justify-content: space-between;
      }
      .menu {
        background-color: #eee;
        display: flex;
        flex-direction: column;
        flex: 1;
        height: 120px;
        justify-content: space-around;
        padding: 8px;
        position: sticky;
        top: 8px;
      }
      .content {
        display: flex;
        flex-direction: column;
        flex: 3;
        justify-content: space-between;
        margin-left: 8px;
      }
      .section {
        height: 100vh;
      }
      .section > h1 {
        background-color: #eee;
        padding: 8px;
        margin-top: 0;
      }
    </style>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script>
      window.addEventListener('load', function() {
        var menuItems = Array.from(document.getElementsByClassName('menu-item'));
        var sections =  Array.from(document.getElementsByClassName('section'));
        menuItems.forEach(function(item, i) {
          var target = sections[i];
          item.addEventListener('click', function() {
            $('html,body').animate({
              scrollTop: window.pageYOffset + target.getBoundingClientRect().top - 8 // 要素がブラウザ上部ぴったりになるので少し隙間をあけました
            }, 500, 'swing');
          });
        });
      });
    </script>
  </head>
  <body>
    <div class="container">
      <div class="menu">
        <a href="#" class="menu-item">section1</a>
        <a href="#" class="menu-item">section2</a>
        <a href="#" class="menu-item">section3</a>
        <a href="#" class="menu-item">section4</a>
        <a href="#" class="menu-item">section5</a>
      </div>
      <div class="content">
        <div class="section"><h1>section1</h1></div>
        <div class="section"><h1>section2</h1></div>
        <div class="section"><h1>section3</h1></div>
        <div class="section"><h1>section4</h1></div>
        <div class="section"><h1>section5</h1></div>
      </div>
    </div>
  </body>
</html>