scrollTo / scrollBy とは何か
scrollTo と scrollBy は、「スクロール位置をプログラムで動かす」ためのメソッドです。window(ページ全体)にも、スクロール可能な要素(overflow: auto 等)にも使えます。ここが重要です:scrollTo は“絶対位置へ移動”、scrollBy は“今の位置から相対移動”。どちらも top(縦)・left(横)をピクセルで指定し、オプションで滑らかなスクロール(behavior: “smooth”)が選べます。
基本の使い方(ページ全体への適用)
絶対位置へスクロール(scrollTo)
<div style="height:2000px"></div>
<script>
// ページ上端から 600px の位置へ移動
window.scrollTo({ top: 600, left: 0, behavior: "smooth" });
</script>
HTMLここが重要です:top/left は“ページ左上”からの絶対座標。behavior: “smooth” を付けるとユーザーの操作感に近い移動になります。一瞬で移動したいなら behavior を省略します。
相対位置へスクロール(scrollBy)
<script>
// 今の位置から 300px 下へ追加で移動
window.scrollBy({ top: 300, left: 0, behavior: "smooth" });
</script>
HTMLここが重要です:scrollBy は“現在位置からの増減”。繰り返し呼び出すステップ移動や「次へ」ボタンに向いています。
要素への適用(パネルやカルーセル)
要素内の絶対位置(scrollTo)
<div id="panel" style="height:160px; overflow:auto; border:1px solid #ccc">
<div style="height:800px"></div>
</div>
<script>
// panel の中で 400px の位置へ移動
panel.scrollTo({ top: 400, left: 0, behavior: "smooth" });
</script>
HTMLここが重要です:window と同じ API を“要素”にも使えます。top/left はその要素の内側スクロール基準(scrollTop/scrollLeft と同じ)です。
要素内の相対移動(scrollBy)
<script>
// 現在から 120px 右へ
panel.scrollBy({ left: 120, behavior: "smooth" });
</script>
HTMLここが重要です:カルーセルや横スクロールリストの「次へ/前へ」操作に最適です。最大・最小値を越えないよう、端判定も合わせて実装します。
よく使うユースケースと丁寧な挙動
要素へスムーズにスクロール(ヘッダの重なり補正付き)
<header style="position:sticky; top:0; height:64px; background:#fff"></header>
<section id="target" style="margin-top:800px">目的地</section>
<script>
function scrollToElement(el, offset = 0) {
const rect = el.getBoundingClientRect();
const y = window.scrollY + rect.top - offset;
window.scrollTo({ top: y, behavior: "smooth" });
}
scrollToElement(target, 64); // 固定ヘッダ分を差し引く
</script>
HTMLここが重要です:固定ヘッダがあると“上に隠れてしまう”問題が起きます。getBoundingClientRect() と現在の scrollY を使って、ヘッダ分を引いた座標に移動すると見やすく止まります。
横スクロール「次へ」ボタンと端判定
<div id="row" style="width:260px; overflow:auto; white-space:nowrap; border:1px solid #ccc">
<span>カード1</span><span>カード2</span><span>カード3</span><span>カード4</span>
</div>
<button id="next">次へ</button>
<script>
function canScrollRight(el) {
return el.scrollLeft < el.scrollWidth - el.clientWidth;
}
function stepRight(el, step = 120) {
if (canScrollRight(el)) el.scrollBy({ left: step, behavior: "smooth" });
}
next.addEventListener("click", () => stepRight(row));
</script>
HTMLここが重要です:右端は scrollWidth−clientWidth。scrollLeft がその値以上なら“もう進めない”。端判定でボタンを無効化すると親切です。
scrollIntoView との違い(どれを使うべきか)
要素を“見えるように”する簡単 API
<script>
// 目的の要素を表示領域へ連れてくる
target.scrollIntoView({ behavior: "smooth", block: "start" }); // "center"/"nearest" も可
</script>
HTMLここが重要です:scrollIntoView は“その要素が見えるまでスクロール”する高レベル API。ページや親要素を自動で選んで動かします。座標を細かく制御したいなら scrollTo/scrollBy、単に見えるようにしたいなら scrollIntoView が手早い選択です。
設計の勘所(なめらかさ・端管理・アクセシビリティ)
なめらかさを守る
- 軽い処理: スクロール中に重い再計算や大量 DOM 更新を入れない。
- 視覚の同期: 進捗バーなどの反映は requestAnimationFrame でまとめる。
- スマホ配慮: CSS の scroll-behavior: smooth が有効なら、JS を減らして CSS で滑らかさを担保するのも有効。
端管理を正確に
- 右端/下端:
scrollLeft >= scrollWidth − clientWidth
scrollTop >= scrollHeight − clientHeight - 安全な分岐:
対策: 端で余分に scrollBy しても何も起きないが、ボタンの disabled を同期すると体験が良くなる。
アクセシビリティの配慮
- フォーカス: 移動後に目的要素へ focus() を当てるとキーボード操作にも優しい。
- ユーザー設定: OS の「視差やアニメを減らす」が有効な環境では、smooth を避けて即時移動に切り替える設計も検討。
落とし穴と回避策
固定ヘッダで隠れる
固定ヘッダぶんを差し引かないと目的地が隠れます。ここが重要です:getBoundingClientRect + scrollY で座標を算出し、ヘッダ高を引いて scrollTo。
相対と絶対の取り違え
scrollTo は絶対、scrollBy は相対。ここが重要です:現在位置を基準にしたステップ移動は scrollBy、特定座標へ一発移動は scrollTo。
スクロール可能でない対象に使う
scrollTo/By は“スクロール可能な対象”にだけ効果があります。ここが重要です:要素側は overflow: auto(または scroll)でスクロール可能にする。window の場合はページが十分な高さ・幅を持っていることが前提です。
重い処理でカクつく
スクロール中のイベントに重い処理を入れると体感が悪化。ここが重要です:passive: true で監視し、描画更新は rAF、計算は最小限に。
まとめ
scrollTo は“絶対位置へ”、scrollBy は“相対位置へ”スクロールさせる基礎メソッドです。window と要素両方に使え、top/left と behavior: “smooth” を組み合わせて直感的な移動を作れます。固定ヘッダの重なりや端判定を丁寧に扱い、必要に応じて scrollIntoView を使い分ければ、“見せたい場所へ正確に・気持ちよく”導けます。処理は軽く、視覚更新は rAF で同期し、フォーカスやアクセシビリティにも目を配ると、初心者でも滑らかで親切なスクロール体験を設計できます。
