DOMを減らした。スクロールも軽い。でも、画像が読み込まれた瞬間に読んでいた場所を見失う。
仮想スクロールには、描画量を減らす仕事に加えて、各行の位置を正しく扱う仕事があります。行の高さが後から変わると、画面に出していない行まで座標に影響します。
GitHubが9月23日に公開した大規模PR表示の解説でも、この問題が登場しました。同社が扱った例は2,200ファイル、100万行超の変更、400件超のインラインコメント。難所のひとつは、描画するまで高さが決まらないコメントだったと説明しています。GitHubの技術解説
AI生成の概念イラスト。内容の高さが変わっても、読み手が見ている場所を保つという課題を表しています。実装図ではありません。
表示していない行にも、高さが要る
たとえば、上から1万行あるリストで、画面周辺の50行だけをDOMに置くとします。これは説明用の数値です。
残りの行を描画しなくても、スクロールバーの長さや、5,000行目の位置は決めなければいけません。
すべての行が20pxなら簡単です。0始まりの行番号を i とすると、上端の座標は 20 × i。
途中に高さの変わるコメントが入ると、座標はこうなります。
行 i の上端 = 行 0 から行 i−1 までの高さの合計
コメントの折り返し、返信欄の展開、画像の読み込み。そのたびに高さの合計が変わります。
描画していないから、計算しなくていいわけではありません。
180px増えたら、読んでいた行も180px動く
以下はGitHubの実測値ではなく、仕組みを説明するための例です。縦方向だけを考え、スクロール範囲の端にはいないものとします。
読んでいる行の上端が文書内の2,000pxにあり、スクロール量が1,900pxなら、画面内では上から100pxの位置に見えます。
画面内の位置 = 文書内の位置 − スクロール量
100 = 2,000 − 1,900
その行より上のコメントが180px伸びると、文書内の位置は2,180pxになります。スクロール量を変えなければ、画面内の位置は280px。読み手には、行が下へ逃げたように見えます。
同じ100pxの位置に保つなら、スクロール量も180px増やします。
補正後のスクロール量 = 1,900 + 180 = 2,080
画面内の位置 = 2,180 − 2,080 = 100
この基準にする要素がアンカーです。W3CのScroll Anchoring仕様草案も、アンカーの移動に応じてスクロール位置を調整する考え方を定めています。仕様草案
下の行が伸びただけなら、上にあるアンカーの座標は変わりません。総高さが変わるたびに無条件でスクロール量を増やす実装では、逆に画面を動かしてしまいます。
ResizeObserverを付けたら完成、ではない
要素のサイズ変化を受け取る手段として ResizeObserver があります。ただし、これは変化の通知です。仮想リストの高さ情報やスクロール位置を、代わりに管理してくれるAPIではありません。MDN
実装を確認するときは、次の流れを追います。
- 変更前に、どの項目のどの位置を画面内に保つか決める。
- サイズ変更を高さ情報へ反映する。
- 同じ項目の新しい座標を求め、必要な分だけスクロール量を補正する。
ここで保存したいのは、単なる「上から何行目」だけではありません。先頭に項目が追加されても同じ内容を追えるように、安定した項目IDが必要です。
ブラウザー側のスクロールアンカリングと、ライブラリ側の補正がどう分担されているかも確認します。独自補正を足す前に、既存の仕組みで何が補正されているかを把握するのが先です。
テストデータは、長くするより途中で変える
固定長の1万行が滑らかでも、可変長コンテンツの確認は終わっていません。
次はリストの途中まで移動してから、読んでいる項目より上の画像を遅れて表示してみてください。続けて、ウィンドウを狭くして文章を折り返す。返信欄を開閉する。
見るのはフレームレートに加えて、同じ項目の同じ場所が、画面内に残っているか です。
項目自体の削除など、同じ場所を維持できない操作には別の方針が要ります。まずは「上の項目だけが伸びる」ケースで、意図しない移動がないかを確かめると原因を絞れます。
仮想スクロールのレビューで、ひとつ聞いてみてください。
このリスト、読み始めた後で高さが変わっても大丈夫ですか?
参考資料
GitHub:Rendering huge pull requests in the GitHub Copilot app(2026年9月23日)
https://github.blog/engineering/user-experience/rendering-huge-pull-requests-in-the-github-copilot-app/
W3C:CSS Scroll Anchoring Module Level 1(Working Draft)
https://www.w3.org/TR/css-scroll-anchoring-1/
MDN:ResizeObserver
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
資料確認日:2026年9月25日。数値例の計算を確認済みです。GitHubの表示性能を独自に測定したものではありません。
