JavaScript で指定した HTML 要素にスクロールさせます。自動的にフォーカスを移動させることなどを想定しています。
よくある処理だと思いますが、そのものズバリのサンプルが見当たらなかったので、実装を残しておきます。
See the Pen ensureVisible by 七誌 (@7shi) on CodePen.
このサンプルでは [Start] をクリックすると、0.5 秒ごとに選択位置を移動して、それに追随してスクロールします。
実装
.NET Framework の ListView
には EnsureVisible
というメソッドがあり、指定した項目が画面外にある場合はスクロールして表示することができます。
それを真似て HTML でも ensureVisible
を実装しました。マージンと HTMLElement を指定します。HTMLElement は複数指定できます。
function ensureVisible(margin, ...elems) {
let rs = elems.map((elem) => elem.getBoundingClientRect());
let tp = Math.min(...rs.map((r) => r.top )) - margin;
let bt = Math.max(...rs.map((r) => r.bottom)) + margin;
if (tp < 0) {
let top = pageYOffset + tp;
scroll({ top, behavior: "smooth" });
} else if (bt > innerHeight) {
let top = pageYOffset + bt - innerHeight;
scroll({ top, behavior: "smooth" });
}
}
位置の指定
getBoundingClientRect は画面上の位置(相対座標)を取得します。スクロールすると変化します。
scroll はドキュメント上の位置(絶対座標)を指定します。そのため表示の開始位置 pageYOffset
を足すことで補正します。今回の実装ではスムーズスクロールを利用しています。
scroll({ top: top, behavior: "smooth" });
スクロール量を指定する scrollBy もありますが、スムーズスクロールをサポートしていないため利用しませんでした。
サンプル
サンプルでは 0.5 秒のウェイトを Promise で処理しています。
function wait(timeout) {
return new Promise((resolve, reject) => setTimeout(resolve, timeout));
}
start.onclick = async () => {
for (let td of Array.from(table.getElementsByTagName("td"))) {
ensureVisible(20, td);
td.classList.add("selected");
await wait(500);
td.classList.remove("selected");
}
ensureVisible(20, moveToTop);
};
詳細は以下の記事を参照してください。
経緯
音声合成の読み上げ位置を追うために実装しました。