8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DOMに getBoundingClientRect() を呼ぶのをやめたら、テキストレイアウトが500倍速くなった話【Pretext】

8
Posted at

フロントエンド開発をしていると、必ずぶつかる壁がある。テキストの高さや幅を動的に取得したいとき、getBoundingClientRect()offsetHeight を呼ぶしかない。でもこれ、呼ぶたびにブラウザが強制的に同期リフローを走らせている。チャットUI、仮想スクロール、マガジンレイアウト——どれもこの問題から逃げられない。

Cheng Louはこれを「DOMへの課税」と呼んでいる。そしてその税金を完全にゼロにするライブラリを作った。名前は Pretext だ。

Cheng Louについて

まず作者を知っておいたほうがいい。Reactのコアコントリビューターであり、ReasonMLとReScriptの作者で、後にMidjourneyのエンジニアを務めた人物だ。新しいフレームワークやCSSの書き方の議論ではなく、「ブラウザがテキストをどう扱うか」という根本に立ち返った。

「地獄の底を這いずり回って、これから数年にわたってUIエンジニアリングの重要な基盤となるものを持ち帰ってきた」

本人がそう言っている。大げさに聞こえるかもしれないが、中身を見ると話が変わってくる。

なぜDOMへの計測依存がまずいのか

getBoundingClientRect() を1回呼ぶだけなら問題ない。問題はそれが繰り返されるときだ。

DOMへの読み取りと書き込みが交互に発生すると「Read/Write Interleaving」と呼ばれる現象が起きる。ブラウザはDOMを読む前に、前の書き込みを反映したレイアウトを再計算しなければならない。大規模なUIでこれが積み重なると、120fpsはおろか60fpsすら維持できなくなる。

仮想スクロールで可変高アイテムを扱うとき、チャットバブルをテキストに合わせてリサイズするとき、レスポンシブな複数カラムレイアウトをリアルタイムに計算するとき——どのケースも同じ問題を抱えている。

Pretextの答え:DOMを一切使わない

Pretextのアプローチはシンプルだ。ブラウザのレンダリングループからレイアウト計算を切り離し、純粋な算術演算だけでテキストの配置を計算する。DOMへの読み取りはゼロ。リフローもゼロ。

APIは2ステップに分かれている。

import { prepare, layout } from '@chenglou/pretext';
 
// ステップ1:テキストを一度だけ解析する(コールドパス)
const handle = prepare(text, '16px Inter');
 
// ステップ2:任意の幅で即座にレイアウトを計算する(ホットパス)
const results = layout(handle, containerWidth, lineHeight);
// → { lines, totalHeight, totalWidth }

解析(prepare)と計算(layout)を分離することで、同じテキストを異なる幅でレイアウトしても、解析コストは一度しかかからない。これがコールドパスとホットパスの分離だ。

Claude CodeとCodexで数週間かけてキャリブレーション

開発プロセスが面白い。このアルゴリズムはClaude CodeとOpenAI Codexを使い、様々なコンテナ幅でブラウザの実際の計測値を記録し続けることで精度を上げていった。数週間の反復の末、ピクセルパーフェクトな精度を実現している。AIツールを使ってAI時代のUIインフラを構築するというのは、象徴的な話だ。

何が実現できるのか

100,000件以上の仮想スクロール at 120fps

可変高アイテムのマソンリーレイアウトを100,000件以上、DOMリフローなしで仮想スクロールできる。これまで「重すぎる」と諦めていた実装が、現実的な選択肢になる。

テキストにぴったり合うチャットバブル

固定幅やCSSのハックに頼らず、テキストの実際の幅にバブルが自動的にフィットする。複数行になっても、短い1行だけのメッセージでも、常に正確にフィットする。

リアルタイムにリフローするマガジンレイアウト

CSS Regionsが約束しながら実現しなかった問題だ。コンテナの幅を変えると、テキストが瞬時に複数カラムに流し込まれる。これが算術演算だけで動いている。

DOMなしで動く環境

Canvas、WebGL、XR環境、サーバーサイドでも動作する。ブラウザのレイアウトエンジンに依存しないということは、ブラウザがなくても使えるということだ。AIエージェントが動的にUIを生成するシナリオでは、この特性が重要になる。

アラビア語・CJK・タイ語の混在レイアウト

スクリプトを意識した混在レイアウトが算術演算レベルで処理される。Emoji特有のCanvas誤差も自動補正される。

AI時代との接点

コミュニティからこんな声が上がっている。

「AIが生成するUIにとって、DOM計測の回避はロードベアリングなインフラだ。インターフェース自体がオンザフライで合成されるなら、リフローのボトルネックは許容できない」

確かにそのとおりだ。AIエージェントが動的にUIを構成する時代において、レイアウト計算がDOMに依存していることは根本的な制約になる。レイアウトが純粋な算術演算で決まるなら、UIはどんな環境でも確定的に生成できる。

導入方法

npm install @chenglou/pretext
# または
bun install @chenglou/pretext

数KBの純粋なTypeScript。ネイティブモジュールもWASMバンドルも不要だ。依存関係はゼロ。

デモは pretextbreaker.com で公開されている。マソンリー仮想化、チャットバブル、ダイナミックマガジン、ASCIIアートなど6つのデモから試せる。GitHubのリポジトリは github.com/chenglou/pretext で公開されている。

まとめ

フロントエンドは長い間、CSSの書き方の議論にエネルギーを注いできた。Pretextはその議論の外から、「DOMに頼らなければよかっただけだ」という答えを持ち込んでいる。

すべてのプロジェクトに必要なわけではない。テキストの計測が1回や2回で済むなら、普通にやればいい。ただ、仮想スクロール、チャットUI、動的マガジンレイアウト、AIが生成するインターフェース——これらを本気で作ろうとしているなら、Pretextは試す価値がある。

「DOMに寸法を頼むのをやめろ。今度はお前が命令する番だ」というのがPretextのメッセージだ。

8
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?