Layout-Reflow ist einer der teuersten Vorgänge im Browser. Wenn man mit getBoundingClientRect() oder offsetHeight die Geometrie eines Elements abfragt, muss der Browser möglicherweise den gesamten Seitenbaum neu berechnen. Bei hunderten von Text-Elementen addiert sich dieser Overhead dramatisch. Pretext von Cheng Lou löst das radikal anders.

Das Problem: Forced Layout

Der Browser ist lazy. Er berechnet Layouts erst wenn er muss. Wenn JavaScript zwischen DOM-Mutationen und Layout-Queries wechselt, entsteht ein Muster das Performance-Experten "Forced Layout" oder "Layout Thrashing" nennen: Der Browser wird gezwungen, wieder und wieder komplett zu relayouten, bevor er irgendwas rendern kann.

Klassischer Anti-Pattern: In einer Schleife erst Elemente mutieren, dann deren Grösse auslesen. Jede Iteration erzwingt einen vollständigen Reflow. Bei 500 Elementen sind das 500 teure Reflows.

Pretexts Ansatz: Prepare einmal, Layout immer

Das Design von Pretext ist konzeptuell elegant: Es teilt Text-Layout in zwei getrennte Phasen.

Phase 1: prepare()

Der prepare()-Schritt nutzt die Canvas-API einmalig um alle nötigen Font-Metriken zu sammeln. Die Canvas-Methode measureText() liefert präzise Informationen über Buchstabenbreiten, Kerning-Paare und Font-spezifische Masse. Diese werden gecacht. Kein DOM-Zugriff, kein Reflow. Dieser Schritt läuft einmal pro Font-Kombination.

Phase 2: layout()

Danach ist layout() reine Arithmetik. Gegeben: Text, verfügbare Breite, gecachte Font-Metriken. Gesucht: exakte Zeilenumbrüche, Zeilenhöhen, Gesamthöhe. Das sind Divisionen, Additionen, Vergleiche. Kein DOM, kein Canvas, kein Browser-API.

~19ms prepare() für 500 Texte
0.09ms layout() für 500 Texte
≈200× Speedup vs. DOM-Messung

Warum Canvas statt DOM?

Die Canvas-API ist der einzige Browser-Mechanismus der präzise Font-Metriken liefert, ohne ein visuelles Layout auszulösen. CanvasRenderingContext2D.measureText() gibt ein TextMetrics-Objekt zurück mit Breite, Ascender, Descender und mehr. Der Canvas muss dafür nicht einmal im DOM sein, er kann vollständig off-screen bleiben.

Das ist die entscheidende Erkenntnis von Cheng Lou: Die Canvas-API wurde als Zeichen-Werkzeug konzipiert, ist aber als Mess-Werkzeug nutzbar. Mit dem richtigen Blickwinkel auf die Plattform verschwindet das Performance-Problem.

Grenzen und Tradeoffs

Pretext ist kein Allheilmittel. Der prepare()-Schritt kostet Zeit und muss bei neuen Font-Kombinationen wiederholt werden. Ausserdem müssen Entwickler selbst das Rendering übernehmen, sei es Canvas, SVG, WebGL oder DOM mit vorberechneten Positionen. Für einfache statische Webseiten ist das Overhead ohne Nutzen.

Für komplexe interaktive Anwendungen aber, für virtuelle Listen, für Echtzeit-Layout-Animationen, für Text-intensive Canvas-Anwendungen, ist die Investition klar lohnenswert. Die Editorial Engine Demo demonstriert 60fps Text-Reflow, der ohne Pretexts Ansatz schlicht nicht möglich wäre.

Fazit

Performance-Probleme löst man entweder durch schnellere Algorithmen oder indem man das Problem vollständig umgeht. Pretext geht den zweiten Weg. Es ist kein schnellerer DOM-Zugriff, es ist gar kein DOM-Zugriff mehr. Das ist die elegantere Lösung.

Layout reflow is one of the most expensive operations in the browser. When you query an element's geometry using getBoundingClientRect() or offsetHeight, the browser may have to recalculate the entire page tree. With hundreds of text elements, this overhead adds up dramatically. Pretext by Cheng Lou solves this in a radically different way.

The Problem: Forced Layout

The browser is lazy. It calculates layouts only when it has to. When JavaScript alternates between DOM mutations and layout queries, a pattern emerges that performance experts call "Forced Layout" or "Layout Thrashing": the browser is forced to fully relayout again and again before it can render anything.

Classic anti-pattern: in a loop, mutate elements first, then read their size. Each iteration forces a full reflow. With 500 elements, that's 500 expensive reflows.

Pretext's Approach: Prepare Once, Layout Forever

The design of Pretext is conceptually elegant: it splits text layout into two separate phases.

Phase 1: prepare()

The prepare() step uses the Canvas API once to collect all necessary font metrics. The Canvas method measureText() provides precise information about letter widths, kerning pairs, and font-specific measurements. These are cached. No DOM access, no reflow. This step runs once per font combination.

Phase 2: layout()

After that, layout() is pure arithmetic. Given: text, available width, cached font metrics. Needed: exact line breaks, line heights, total height. These are divisions, additions, comparisons. No DOM, no Canvas, no browser API.

~19ms prepare() for 500 texts
0.09ms layout() for 500 texts
≈200× Speedup vs. DOM measurement

Why Canvas Instead of DOM?

The Canvas API is the only browser mechanism that provides precise font metrics without triggering a visual layout. CanvasRenderingContext2D.measureText() returns a TextMetrics object with width, ascender, descender, and more. The canvas doesn't even need to be in the DOM, it can remain completely off-screen.

This is the key insight from Cheng Lou: the Canvas API was designed as a drawing tool, but it's usable as a measurement tool. With the right perspective on the platform, the performance problem disappears.

Limits and Tradeoffs

Pretext is not a silver bullet. The prepare() step takes time and must be repeated for new font combinations. Developers also have to handle rendering themselves, whether Canvas, SVG, WebGL, or DOM with precomputed positions. For simple static websites, this is overhead without benefit.

For complex interactive applications, virtual lists, real-time layout animations, and text-intensive canvas applications, the investment is clearly worthwhile. The Editorial Engine Demo demonstrates 60fps text reflow that simply wouldn't be possible without Pretext's approach.

Conclusion

Performance problems are solved either by faster algorithms or by completely avoiding the problem. Pretext takes the second route. It's not faster DOM access, it's no DOM access at all. That's the more elegant solution.