// A daily devlog.

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.
GitHub - lusionltd/WebGL-Scroll-Sync favicon github.com
GitHub - lusionltd/WebGL-Scroll-Sync

ポイントはかなりシンプルで、

  • ネイティブスクロールは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なしでどこまで気持ちよくできるか」を考えると、かなり実用的な落としどころでした。

以上、おわり。