2026-02-19
WebGLとDOMのスクロール同期、スマホだけズレる問題のメモ
fixedキャンバスで起きる追従遅れを、scroll-jackingなしで減らすLusion方式。
DOMでレイアウトした画像を、WebGLの1枚canvasで追従描画する構成ってありますよね。
このときスマホだけ「位置がズレる」「追従が遅れて見える」問題にハマりました。
参考にしたのはLusionのこちら。
GitHub - lusionltd/WebGL-Scroll-Sync
Contribute to lusionltd/WebGL-Scroll-Sync development by creating an account on GitHub.
ポイントはかなりシンプルで、
- ネイティブスクロールは
requestAnimationFrameと完全同期しない - スクロールが
rAFの合間に進むと、canvas側は次フレームまで古い位置で描画される - 結果として「DOMは進んでるのにWebGLだけ遅れて見える」
Lusionの発想転換
よくある回避策はLenisなどでスクロール自体をrAF同期に寄せる方法(いわゆるscroll-jacking)ですが、Lusionは逆方向で、canvasをfixedにしないやり方を取っています。
- canvasを
position: fixedではなくposition: absoluteにする - ページと一緒にcanvas自体も物理的にスクロールさせる
rAF中にtopオフセットをscrollYに合わせて調整する
これで、rAFの合間にスクロールしてもcanvasがDOMと一緒に動くので、
「WebGLだけ置いていかれる感」がかなり減ります。
実運用だと、
- いっそscroll-jackingする
- スマホだけWebGL演出を切る
という選択もよくあります。
ただ自分の感覚では、スマホはネイティブ慣性が強いぶん、scroll-jackingを重ねると「指と画面のズレ感」が出やすい。
なのでスマホでもWebGLを活かしつつズレを減らす方法何かないかなとGitHubやSNSなど探し回りました。
トレードオフ
ただ、この方式は万能ではなくて、弱点もあるんですよね。
- 高速スクロール時にcanvasの描画範囲外が見えて、クリップが出ることがある
- canvasを
fixedでビューポート固定する前提は崩れる(absolute運用になる)
クリップが出る対策としては、
- canvas上下に余白を持たせて多めに描画する(デモだと上下25%)
- 余裕があればframebufferで端をフェードする
「scroll-jackingなしでどこまで気持ちよくできるか」を考えると、かなり実用的な落としどころでした。
以上、おわり。