【実務・中級編】 コンポジタースレッドの役割 – Webブラウザの仕組み実践ガイド

「君の書いたアニメーション、なんでこんなにガタつくんだ?」

現場でそんな厳しい言葉を投げかけられたことはないかな。あるいは、複雑なJavaScriptを回している最中にスクロールがカクついて、ユーザー体験が台無しになる瞬間を。

フロントエンド・エンジニアとして中級の壁を超えるには、DOMを操作したりAPIを叩いたりするスキルの先に、「ブラウザという巨大なソフトウェアが、どうやってピクセルを画面に叩き出しているか」というアーキテクチャの理解が不可欠だ。

今日は、レンダリング・パイプラインの守護神、「コンポジタースレッド(Compositor Thread)」の正体について話をしよう。こいつを味方に付けられるかどうかで、君の作るプロダクトの「手触り」は劇的に変わる。

—

1. メインスレッドという「超過密労働」の現場

ブラウザの裏側で何が起きているか、まずは現状を整理しよう。

僕たちが書くJavaScriptの実行、DOMの構築、スタイルの計算、そしてレイアウト(リフロー)やペイント(リペイント)。これらはすべて「メインスレッド」という一つの場所で行われている。

想像してみてほしい。メインスレッドは、一人で何役もこなす超多忙な舞台監督だ。

  • JSの重い計算をこなす
  • ユーザーのクリックをさばく
  • 要素の大きさを計算する
  • 色を塗る

ここで問題が起きる。JSのループが100ms止まったらどうなる? その間、舞台監督は「色の塗り直し」も「配置の変更」もできない。結果として、画面はフリーズし、ユーザーのスクロール操作すら受け付けなくなる。これが「ジャンク(Jank)」の正体だ。

2. コンポジタースレッド:独立した「描画の専門職」

この地獄のような状況を救うために、モダンブラウザ(Chromeなど)にはコンポジタースレッドという独立したスレッドが存在する。

コンポジタースレッドの役割は、メインスレッドから「ページの断片(レイヤー)」を受け取り、それらを組み合わせて(合成して)最終的な画面を生成することだ。

最大の特徴は、「メインスレッドがJSの計算で死んでいようが、コンポジタースレッドは独立して動き続けられる」という点にある。

なぜスクロールは滑らかなのか?

最近のブラウザでは、スクロール処理はコンポジタースレッドが担当している。メインスレッドが重い処理をしていても、すでに描画済みのレイヤーを上下にずらすだけなら、コンポジタースレッドだけで完結できる。だから、JSが固まっていてもスクロールだけは動く、という挙動が可能なんだ。

—

3. 「レイヤー」という魔法の概念

コンポジタースレッドが効率よく動くために、ブラウザはページをいくつかの「レイヤー(Graphics Layers)」に分割する。

Photoshopのレイヤーを思い浮かべてほしい。背景レイヤーと、動くキャラクターのレイヤーが分かれていれば、キャラクターを動かすときに背景を塗り直す必要はないよね? これと全く同じことがブラウザ内でも起きている。

1. メインスレッドが「どの部分をレイヤーにするか」を決め、描画内容をラスタライズ(ピクセル化)する。
2. その情報をGPUメモリにアップロードする。
3. コンポジタースレッドは、GPUに対して「このレイヤーをこの位置に、この角度で表示しろ」と命令を送るだけ。

この「命令を送るだけ」というのがポイントだ。ピクセルを塗り直す(ペイント)のではなく、既存のビットマップを移動させるだけなので、圧倒的に速い。

—

4. 実戦:コンポジタースレッドを活かすコード、殺すコード

ここで、実務で明日から使える知識を共有しよう。
特定のアニメーションプロパティは「コンポジタースレッドだけで完結する」が、それ以外は「メインスレッドを叩き起こす」必要がある。

避けるべき例:`top` / `left` によるアニメーション

/ ❌ メインスレッドを苦しめる書き方 /
.box {
position: absolute;
top: 0;
transition: top 0.3s;
}
.box:hover {
top: 100px; / レイアウト(リフロー)が発生し、メインスレッドが計算し直す /
}

`top`や`left`を変えると、その要素の周りの配置にも影響が出る可能性がある。ブラウザは「念のためレイアウト全体を再計算しなきゃ!」と判断し、メインスレッドで重い処理を走らせてしまう。

推奨される例:`transform` と `opacity`

/ ✅ コンポジタースレッドに任せる書き方 /
.box {
will-change: transform; / ブラウザに「これ、後で動くからレイヤー化しといて」とヒントを出す /
transition: transform 0.3s;
}
.box:hover {
transform: translateY(100px); / GPUがレイヤーをずらすだけ。メインスレッドは関与しない /
}

`transform`と`opacity`は、他の要素のレイアウトに影響を与えないことが保証されている。そのため、コンポジタースレッドがGPUと直接連携して処理できる。これが「ヌルヌル動く」アニメーションの鉄則だ。

—

5. 現場で使える「レイヤー隔離」のサンプル

では、実際にコンポジタースレッドの恩恵を最大化するためのコード例を見てみよう。






このコードで何が起きるか?

「メインスレッドを3秒フリーズさせる」ボタンを押してみてほしい。
普通のJS処理なら、画面上のすべてが固まるはずだ。しかし、`transform`でアニメーションさせている青いボールは、JSがフリーズしている間も止まることなく滑らかに動き続ける。

これが、コンポジタースレッドの力だ。

---

6. シニアからのアドバイス:武器を正しく使うために

最後に、この仕組みを知った君に気をつけてほしいことが二つある。

1. `will-change` を乱用しないこと:
「何でもかんでもレイヤーに分ければ速くなる」というのは間違いだ。レイヤーを作るということは、その分GPUメモリを消費する。メモリが不足すれば、ブラウザは逆に遅くなる。アニメーションが必要な「ここぞ」という要素にだけ使おう。

2. DevToolsの「Layers」パネルを見ること:
Chrome DevToolsの「三点リーダー」→「More tools」→「Layers」を見てごらん。自分のサイトがどうレイヤー分割されているか視覚的に確認できる。意図しない巨大なレイヤーが作られていないかチェックする癖をつけよう。

ブラウザの仕組みを理解してコードを書くことは、単に「動くものを作る」こととは次元が違う。それは、ユーザーが感じる「心地よさ」の設計そのものなんだ。

次は、ラスタライズの並列化についても話したいが……今日はこの辺にしておこう。まずはこのコンポジタースレッドの仕組みを、自分のプロジェクトで試してみてくれ。健闘を祈る!

コメント

タイトルとURLをコピーしました