【JavaScript】スクロールの開始位置を一番下にする方法

JavaScript

スクロールの開始位置を一番下にする方法、つまり下から上に向かってスクロールするUIを実現する方法について紹介します。

スクロールの開始位置を一番下にする方法

スクロールの開始位置を一番下にする方法
  • 方法1: スクロールを操作してスクロール位置を一番下に移動させる
  • 方法2: Flexboxを適用し、Flexアイテムの配置方向を下から上にする

以下では上記の方法の詳細について紹介します。

方法1: スクロールを操作してスクロール位置を一番下に移動させる

スクロールに関するメソッドを利用することでスクロールの位置を一番下に移動させる方法です。

今回はscrollIntoViewscrollTopscrollToを利用する方法について紹介します。

scrollIntoViewscrollToscrollTopの詳細解説は【JavaScript】スクロール操作に関する基礎知識で紹介しています。

scrollIntoViewを利用する方法

scrollIntoViewは要素が見える位置まで親要素をスクロールするメソッドです。

スクロール全体を囲む要素に対してscrollIntoView(false)を適用することでスクロールが一番下に移動します。
scrollIntoView(false)scrollIntoView({ block: "end", inline: "nearest" })と等価です。

<div class="scroller">
  <div id="scroller__inner">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </div>
</div>

.scroller {
  overflow: scroll;
  height: 100px;
  padding: 10px;
  margin-bottom: 5px;
  width: 150px;
  border: 5px dashed orange;
}

const scrollerInner = document.getElementById("scroller__inner");

// scrollerInner.scrollIntoView({block: "end", inline: "nearest"}) でもOK
scrollerInner.scrollIntoView(false);

See the Pen
scroll-bottom-block-end
by Toshiharu Nishina (@nishina555)
on CodePen.

scrollTopを利用する方法

scrollTopはスクロールの一番上から現在のスクロール位置までのピクセル数を保存するプロパティで、任意の値を設定できます。

画面上に見えていないスクロールの高さ分だけスクロールさせた時、スクロールは一番下にきます。

「画面上に見えていないスクロールの高さ」とは「スクロール全体の高さ」から「画面上に見えているスクロール画面の高さ」を引いた値です。
つまり、スクロールの一番上からの移動距離(scrollTop)をscrollHeight - clientHeightにすることでスクロールが一番下になります。

<div class="scroller" id="scroller">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
<div>clientHeight: <span id="client-height"></span></div>
<div>scrollTop: <span id="scroll-top"></span></div>
<div>scrollHeight: <span id="scroll-height"></span></div>

.scroller {
  overflow: scroll;
  height: 100px;
  padding: 10px;
  margin-bottom: 5px;
  width: 150px;
  border: 5px dashed orange;
}

const scroller = document.getElementById('scroller');

scroller.scrollTop = scroller.scrollHeight - scroller.clientHeight;

// 以下はデバッグ用のログ出力
scroller.addEventListener("scroll", event => {
  document.getElementById("scroll-top").textContent = `${scroller.scrollTop}`;
  document.getElementById("client-height").textContent = `${scroller.clientHeight}`;
  document.getElementById("scroll-height").textContent = `${scroller.scrollHeight}`;
});

See the Pen
scroll-bottom-block-end-scrollTop
by Toshiharu Nishina (@nishina555)
on CodePen.

scrollToを利用する方法

scrollToはスクロールを指定した位置に移動させるメソッドです。
画面上に見えていないスクロールの高さ、つまりscrollHeight - clientHeight分だけスクロールを移動させることでスクロールが一番下にきます。

<div class="scroller" id="scroller">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
<div>clientHeight: <span id="client-height"></span></div>
<div>scrollTop: <span id="scroll-top"></span></div>
<div>scrollHeight: <span id="scroll-height"></span></div>

.scroller {
  overflow: scroll;
  height: 100px;
  padding: 10px;
  margin-bottom: 5px;
  width: 150px;
  border: 5px dashed orange;
}

const scroller =  document.getElementById('scroller');

// scroller.scrollTo({ top: scroller.scrollHeight - scroller.clientHeight, left: 0, behavior: 'auto' }); でもOK
scroller.scrollTo(0, scroller.scrollHeight - scroller.clientHeight);

// 以下はデバッグ用のログ出力
scroller.addEventListener("scroll", event => {
  document.getElementById("client-height").textContent = `${scroller.clientHeight}`;
  document.getElementById("scroll-top").textContent = `${scroller.scrollTop}`;
  document.getElementById("scroll-height").textContent = `${scroller.scrollHeight}`;
});

See the Pen
scroll-bottom-block-end-scrollTo
by Toshiharu Nishina (@nishina555)
on CodePen.

方法2: Flexboxを適用し、Flexアイテムの配置方向を下から上にする

スクロールにFlexboxを適用し、Flexアイテムの配置方向を下から上にすることでスクロールの開始位置が下になります。
Flexboxを利用するだけですのでJavaScriptの実装は不要です。

Flexアイテムの配置方向を下から上にした場合、scrollTopの正負は逆になるので注意が必要です。

Flexboxの詳細解説はFlexboxの概要と使いどころで紹介しています。

<div class="scroller" id="scroller">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
<div>clientHeight: <span id="client-height"></span></div>
<div>scrollTop: <span id="scroll-top"></span></div>
<div>scrollHeight: <span id="scroll-height"></span></div>

.scroller {
  overflow: scroll;
  height: 100px;
  padding: 10px;
  margin-bottom: 5px;
  width: 150px;
  border: 5px dashed orange;
  display: flex;
  flex-direction: column-reverse; /* Flexアイテムの配置方向を下から上にする */
}

// デバッグ用のログ出力
const scroller = document.getElementById('scroller');
scroller.addEventListener("scroll", event => {
  document.getElementById("scroll-top").textContent = `${scroller.scrollTop}`;
  document.getElementById("client-height").textContent = `${scroller.clientHeight}`;
  document.getElementById("scroll-height").textContent = `${scroller.scrollHeight}`;
});

See the Pen
scroll-bottom-flexbox
by Toshiharu Nishina (@nishina555)
on CodePen.

一番上までスクロールされたことを検知する方法

スクロールを操作してスクロール位置を一番下に移動させた場合

scrollIntoView、scrollTop、scrollToを利用したケースです。
scrollTop == 0の真偽値によって判定できます。

<div class="scroller" id="scroller">
  <div id="scroller__inner">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </div>
</div>
<div>clientHeight: <span id="client-height"></span></div>
<div>scrollTop: <span id="scroll-top"></span></div>
<div>scrollHeight: <span id="scroll-height"></span></div>
<div id="scroll-status">Scroll to the top</div>

.scroller {
  overflow: scroll;
  height: 100px;
  padding: 10px;
  margin-bottom: 5px;
  width: 150px;
  border: 5px dashed orange;
}

#scroll-status {
  width: 150px;
  padding: 5px;
  border: #2A9F00 solid 2px;
}

const scroller = document.getElementById('scroller');
const scrollerInner = document.getElementById("scroller__inner");

scrollerInner.scrollIntoView(false);

scroller.addEventListener("scroll", event => {
  const clientHeight = scroller.clientHeight;
  const scrollHeight = scroller.scrollHeight;
  const scrollTop = scroller.scrollTop;

  // 一番上までスクロールされたか判定
  if (scrollTop == 0) {
    document.getElementById("scroll-status").textContent = `Thank you`;
  }

  // 以下はデバッグ用のログ出力
  document.getElementById("client-height").textContent = `${clientHeight}`;
  document.getElementById("scroll-top").textContent = `${scrollTop}`;
  document.getElementById("scroll-height").textContent = `${scrollHeight}`;
});

See the Pen
scroll-totally-from-bottom-block-end
by Toshiharu Nishina (@nishina555)
on CodePen.

Flexboxを適用し、Flexアイテムの配置方向を下から上にした場合

scrollTopの正負が逆転するだけで、考え方は【JavaScript】スクロール操作に関する基礎知識で紹介している「一番下までスクロールされたことを検知する方法」と同じです。

「画面上に見えているスクロール画面の高さ」と「実際にスクロールした高さ」の合計が「スクロール全体の高さ」になった状態は、一番上までスクロールされたことを意味します。
scrollTopの正負が逆転している点に注意すると、clientHeight - scrollTop === scrollHeightという条件式の真偽値によって一番上までスクロールされたことを検知できます。

scrollTopは小数点を含む可能性のあるプロパティであることを考慮し、Math.abs(scrollHeight - clientHeight + scrollTop) < 1の判定式を利用するとより確実です。

<div class="scroller" id="scroller">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
<div>clientHeight: <span id="client-height"></span></div>
<div>scrollTop: <span id="scroll-top"></span></div>
<div>scrollHeight: <span id="scroll-height"></span></div>
<div id="scroll-status">Scroll to the top</div>

.scroller {
  overflow: scroll;
  height: 100px;
  padding: 10px;
  margin-bottom: 5px;
  width: 150px;
  border: 5px dashed orange;
  display: flex;
  flex-direction: column-reverse;
}

#scroll-status {
  width: 150px;
  padding: 5px;
  border: #2A9F00 solid 2px;
}

const scroller = document.getElementById('scroller');

scroller.addEventListener("scroll", event => {
  const clientHeight = scroller.clientHeight;
  const scrollHeight = scroller.scrollHeight;
  const scrollTop = scroller.scrollTop;
  if (Math.abs(scrollHeight - clientHeight + scrollTop) < 1) {
    document.getElementById("scroll-status").textContent = `Thank you`;
  }
  // 以下はデバッグ用のログ出力
  document.getElementById("client-height").textContent = `${clientHeight}`;
  document.getElementById("scroll-top").textContent = `${scrollTop}`;
  document.getElementById("scroll-height").textContent = `${scrollHeight}`;
});

See the Pen
scroll-totally-from-bottom-flexbox
by Toshiharu Nishina (@nishina555)
on CodePen.

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!