HTML-in-Canvas: Vorschlag für eine neue API zum direkten Rendern von HTML-Inhalten im Canvas
(github.com/WICG)- HTML-in-Canvas ist ein WICG-Projekt, das eine neue Standard-API vorschlägt, mit der HTML-Elemente bzw. -Inhalte direkt innerhalb von
<canvas>gezeichnet werden können - Es wurde eingeführt, um komplexes Textlayout, Accessibility, Internationalisierung sowie Qualitäts-/Performance-Probleme zu adressieren, und macht in Charts, UI und Spielmenüs sowie weiteren Canvas-Anwendungsfällen direktes HTML-Styling nutzbar
- Über neue Methoden wie
drawElement,texElement2DundsetHitTestRegionslassen sich HTML-Elemente unverändert im Canvas 2D- oder WebGL-Kontext rendern und texturieren - Interaktionsbereiche, Accessibility-Verbesserung, 2D-UI in 3D-Szenen, CSS-/HTML-basierte Layouts etc. spiegeln echte Anforderungen von Web-App-Entwicklern wider
- Derzeit kann es in Chrome Canary (ab 138.0.7175.0) über einen experimentellen Flag aktiviert werden; Feedback und Bugreports sind willkommen
Übersicht und Bedeutung
- Eine neue API, mit der HTML-Elemente direkt in
<canvas>gerendert werden können, wird vorgeschlagen - Bisher gab es keinen einfachen Weg, komplexe Layouts sowie Text- und HTML-basierte Inhalte in
<canvas>zu rendern, was zu Einschränkungen bei Accessibility, Internationalisierung, Performance und Qualität führte - HTML-in-Canvas adressiert diese Lücke, indem es HTML-Rendering in 2D-Canvas und WebGL unterstützt und so Einsatzmöglichkeiten bei Charting-Tools, Rich-Text-Feldern und Spiel-UIs erweitert
Anwendungsfälle
- Darstellung formatierter Text- und Layoutinhalte im Canvas
- Beispiele: Legenden und Achsen von Diagrammen, Rich-Text-Editor-Felder, Menüs im Spiel
- Bessere Accessibility
- Beseitigt Inkonsistenzen zwischen alternativer Canvas-Beschreibung und tatsächlich gerenderten Inhalten
- Mit der neuen API lassen sich Accessibility-Informationen besser synchron halten
- Kombination von HTML und WebGL-Shadern
- Reagiert auf den Bedarf, über reine CSS-Filter-Effekte hinaus HTML mit regulären WebGL-Shadern zu kombinieren
- HTML-Rendering in einem 3D-Kontext
- Ermöglicht den Einsatz von reichhaltigen 2D-Inhalten in 3D-Bereichen von Spielen oder Websites
Vorgeschlagene API und Hauptfunktionen
- Die Eigenschaft
<canvas layoutsubtree>aktiviert das Layout untergeordneter HTML-Elemente im Canvas (standardmäßig wird nur visuell gerendert; sie werden nicht in UA-Algorithmen für Seiten-Navigation etc. berücksichtigt) - CanvasRenderingContext2D.drawElement(element, x, y, options)
- Rendert ein Canvas-Kind-HTML-Element an der angegebenen Position
- Mit
options.allowReadbacklässt sich das Verhindern von Datenabfluss steuern (zukünftig mit einer Tainting-Policy) - Mit den Parametern
dwidth/dheightkann auf Wunsch die Größe angepasst werden
- WebGLRenderingContext.texElement2D(...)
- Zeichnet ein angegebenes HTML-Element direkt als WebGL-Textur und nutzt es in 3D-Szenen
- setHitTestRegions
- Verknüpft die im Zeichnungsbereich liegenden Elemente mit Canvas-Ereignissen (Hit Testing), um Maus-/Touch-Events automatisch umzuleiten
- fireOnEveryPaint-Option (ResizeObserver)
- Erkennt bei Änderungen oder Repositionierungen von HTML automatisch neu, wann ein Re-Render erforderlich ist, und triggert das erneute Zeichnen
Verhalten und Einschränkungen
- Bei einem
drawElement-Aufruf wird die Canvas-Transform-Matrix (CTM) berücksichtigt; die Zeichnung wird auf die Border Box des Elements geclippt - Das auf das Canvas gezeichnete Bild ist statisch (ändert sich das Element danach, ist ein erneuter
drawElement-Aufruf nötig) - Für Offscreen-Canvas bzw. Canvas-Instanzen ohne DOM-Einbindung ist es nicht unterstützt
- Interaktive Elemente (Buttons, Formulare etc.) lassen sich zeichnen, werden aber nicht automatisch interaktiv
- Cross-Origin-Iframes und
SVG foreignObjectwerden nicht unterstützt - Accessibility-, Sicherheits- und Datenschutz-Themen (insbesondere PII) werden weiterhin diskutiert
Demo-Beispiele
- Komplexer-Text-Beispiel: Zeichnet komplexes Layout direkt mit
drawElement, darunter HTML-gestylter Text und Boxen, auf das Canvas - WebGL-Beispiel: Erstellt mit
texElement2Deine WebGL-Textur aus HTML-Inhalten und mappt sie auf einen 3D-Würfel - Text-Eingabe-Beispiel: Zeigt, wie
setHitTestRegionsundfireOnEveryPaintverwendet werden, um klickbare Zonen wie Eingabeformulare zu markieren
Entwickler-Tests und Hinweise
- Aktivierung in Chrome Canary über den Flag
--enable-blink-features=CanvasDrawElement - Canvas-Inhalte sind nicht automatisch getainted, daher ist Sorgfalt bei der Vermeidung von Datenschutzverletzungen zwingend
- API und Verhalten ändern sich weiterhin; groß angelegte Testfälle für HTML sind noch begrenzt
- Feedback ist erwünscht: Bitte kompatibilitäts-, Render-Failure- und Accessibility-Fälle als GitHub-Issue melden
Nutzen und Ausblick
- In Bereichen wie Charts, Datenvisualisierung, In-Canvas-UI sowie HUDs und Menüs in 3D-Spielen steigert die API die Ausdruckskraft und Produktivität im Web deutlich
- Die bisher aufwendige HTML→Canvas-Umsetzung (Styling, Layout, Mehrsprachigkeit, Accessibility) lässt sich künftig direkt über eine Standard-API abbilden
- Für Entwickler in den Bereichen Web-Grafik, Spiele und Apps ist dies als starke neue Technologie zu erwarten
1 Kommentare
Hacker News Kommentar
Ich stimme zu, dass es zwar viele Sorgen um Barrierefreiheit und Missbrauch gibt, aber man sollte die andere Seite dieser Diskussion ebenfalls sehen. Kürzlich habe ich auf X einen interessanten Thread gesehen, in dem behauptet wurde, dass 90 % der guten Dinge im Web nicht passieren, weil Font-Rendering und Metriken in JS nicht verfügbar seien. Das Web sei als Plattform für Textdarstellung entworfen, aber ohne fein-granulare Textfunktionen; außerdem wurde die Reaktion geäußert, dass es schade sei, dass tldraw die Textmessung mit Gewalt nachbauen müsse. (Twitter-Thread: https://x.com/_chenglou/status/1951481453046538493) Das Web ist eine Plattform zur Anwendungsentwicklung, sodass es für alle gut wäre, sie leicht und leistungsfähig zu machen. Ich halte es für richtig, dass Web-APIs niedriger ansetzen sollten; eine Font-/Textmetrik-API für Canvas wäre fantastisch. Gleichzeitig ist das Textlayout der Browser-Engines enorm performant, daher wäre es großartig, wenn solche Funktionen auch im Canvas intern genutzt werden könnten. Ein Beispiel, auf das ich seit Jahren immer wieder komme, ist „paginierte Rich-Text-Bearbeitung“: Mit
contenteditableallein ist keine Produktreife möglich, weshalb Google Docs eine eigene Layout-Engine gebaut hat. Wenn dieser Vorschlag umgesetzt wird, kann man die Stärke voncontenteditablemit der Möglichkeit verbinden, Seiten- und Drucklayouts zu kontrollieren. Ich hoffe, diese Funktion wird im Browser umgesetzt.Der Behauptung, dass die meisten guten Dinge im Web daran scheitern, dass Font-Rendering und Metriken in JS nicht nutzbar sind, stehe ich etwas skeptisch gegenüber. Ich würde gerne wissen, welches wirklich repräsentative Innovationsbeispiel dahintersteckt. Schon heute werden in JS schon eine Menge Font- und Metrikinformationen bereitgestellt, und die meisten benötigten Features lassen sich mit Ausweichwegen ohne gravierende Performanceprobleme implementieren. Außerdem ist es nicht so, dass das, was HTML-in-Canvas liefert, dort einen Grundwandel bringt.
Ich setze in Nutrient wie Google Docs ebenfalls HarfBuzz und eine eigene Layout-Engine auf WASM-Basis ein. Demo: https://document-authoring-demo.nutrient.io/ Wenn diese API offiziell von der Plattform bereitgestellt wird, wäre die Entwicklung deutlich einfacher. Dank WASM gibt es keinen echten Dead End. Ich habe gehört, dass bei ElectricSQL gerade die Synchronisierung läuft, also Grüße an Oleksii.
Auf den Satz „Ich hoffe, diese Funktion wird im Browser umgesetzt“ bezogen verstehe ich nicht, warum man die ineffizienteste Layout-/UI-Engine der Welt auf Canvas ausdehnen will. Dadurch würde man das bestehende Problem mangelnden API-Zugriffs nur zementieren. Figma löst die DOM-Grenzen, indem es innerhalb des Browsers einen weiteren Browser einbettet (siehe: https://www.figma.com/blog/building-a-professional-design-to...). Wenn
contenteditableallein keine produktionsreife Implementierung im Produktmaßstab ermöglicht und deswegen Google Docs eine eigene Engine gebaut hat, wird dieser Vorschlag am Nutzen für Rich-Text-Layout kaum zulegen.Ich halte diese Funktion zwar für nützlich, aber die Struktur, HTML in Canvas zu legen, in der ein HTML-Dokument sitzt, wirkt irgendwie merkwürdig und passt nicht wirklich. Ich denke, Canvas sollte im Browser ein eigenständiges First-Class-Format werden, dann kann man es sinnvoll kombinieren. Dann wäre es natürlich, HTML mit Canvas zu ergänzen oder umgekehrt Canvas mit HTML-Elementen zu verbinden. Das ist natürlich nur meine Sichtweise.
Deinem Einwand ist absolut nichts aus heutiger Sicht falsch. Man kann HTML bereits in SVG, wieder in HTML usw. einbetten. Wenn Canvas die Top-Ebene der Seite wäre, wo speichert man dann den Seitentitel? Letztlich braucht man ein ``-Tag, etwa so:
Würde man praktisch erlauben, Inhalte im Canvas-Tag selbst unterzubringen, wäre das ganz einfach zu lösen:
Canvas-zentrierte Websites sind unbequem. Man kann keine vollständigen Systemdienste wie Autovervollständigung und Accessibility nutzen, und es gibt Datenschutzfragen. Ein Beispiel: Die systemeigene Rechtschreibprüfung lässt sich schwer nutzen, und Accessibility funktioniert nicht nativ, sodass jede App direkt eigene, komplett unterschiedliche Accessibility-UIs bauen müsste.
In diesem Ansatz würdest du praktisch Flash neu erfinden. Allerdings war es auch beim Einstieg von Flash ins Web ein enormer Aufwand.
Es gibt Fälle, in denen man in einer HTML-Seite einen Canvas hat und dem darinstehenden Text Layout- und Styling-Funktionen geben will. Dafür das gesamte Seitenlayoutmodell umzubauen wäre unnötig komplex.
Früher gab es Gegenwind gegen DOM-Zugriff per WASM. Deshalb sehe ich diesen Entwicklungsweg als unausweichlich.
Wir sind inzwischen an einem Punkt gekommen, an dem wir den kompletten Browser zu WASM kompilieren und ihn dann im Canvas-Element des Hauptbrowsers ausführen.
Damit ist es sogar möglich, ein komplettes OS inklusive IE im Web auszuführen (Beispiel: https://copy.sh/v86/?profile=windows2000)
Das erinnert an die Prämisse des bekannten Talks „The Birth & Death of JavaScript“. Siehe: https://www.destroyallsoftware.com/talks/the-birth-and-death...
Auch hier gibt es den Versuch https://www.chromium.org/blink/blink-in-js/
Wegen der Themen „Sandboxing und Sicherheit“ könnte diese Struktur in Zukunft sogar zwingend werden.
Als Referenz kann man sich hier eine ähnliche Umgebung ansehen: https://trevorlinton.github.io
In https://github.com/WICG/html-in-canvas/blob/main/security-privacy-questionnaire.md steht: dass das TODO für Fingerprinting-Risiken ergänzt werden muss.
Ich denke, dass man mit dem SVG-Tag
foreignObjectbereits ähnliche Ergebnisse wie bei HTML-in-Canvas erzielen kann. Beispielsweise gibt es Projekte wie https://github.com/zumerlab/snapdom, die den DOM mit Inline-Styles kopieren und in ein SVG-foreignObjecteinbetten und anschließend auf Canvas rendern.foreignObjectin Canvas einfacher. Zusätzlich werden neue Features unterstützt, etwa automatische Updates bei Inhaltsänderungen und Interaktivität.Vielleicht liege ich falsch, aber ich habe das Gefühl, dass reines JS es bereits ermöglicht, HTML auf Canvas zu rendern. Canvas wird eingesetzt, wenn man Dinge zeichnen muss, die HTML nicht kann; es soll nicht den DOM ersetzen.
Aktuell wären beispielsweise
Wenn HTML-Elemente oberhalb von allem im Canvas liegen, ist das okay; wenn nicht, braucht man wieder Canvas über HTML, also Wiederholungen je z-Schicht. Diese Änderung könnte den „umgekehrten Rendering-Layer-Stack“ des Browsers endlich reparieren. Ich bin der Meinung, dass alle Browser-Renderings auf einer universellen Canvas-API aufbauen sollten.
Wir werden bald vielleicht wieder Canvas-Rendering innerhalb von HTML-in-Canvas brauchen.
Das ruft sofort das „Pimp My Ride“-Meme hervor. „Kumpel, du magst HTML, also habe ich HTML in Canvas gesetzt und darin noch ein Canvas eingebaut.“
Vielleicht wäre es eine Idee, dem
body-Element einfach ein Flag zu geben:Dadurch würde die gesamte Seite dieselbe Zeichenoberfläche wie Canvas werden und man könnte DOM-Elemente wie gewohnt rendern. Wenn man den internen Rasterisierungspfad für DOM öffnet, wäre das noch besser. Architekturseitig würden DOM-Rendering und Canvas-Rendering dann vollständig gleichwertige Ebenen bilden. Beispielsweise könnte man Aktionen wie das Zeichnen von Linien steuern, sodass sie einen DOM-Reflow auslösen oder nicht.
Ich stelle mir den Moment vor, in dem alle Screenreader gleichzeitig durchdrehen.
Mit diesem Ansatz könnte Canvas automatisch skalieren; falls das so wäre, wäre es der Beginn einer neuen Ära der HTML-Kombination.
iframekönnte dadurch übertroffen werden.Es fühlt sich zwar seltsam an, aber ich stimme dem Vorschlag eher zu. Man greift oft auf bestehende HTML-Elemente zurück, wenn etwas gerendert werden soll. Früher hat man das oft off-screen zu einem Bitmap gerendert und auf Canvas kopiert oder versucht, über
z-indexundposition absolutezu justieren, doch Canvas überlagerte das immer visuell (das ist in letzter Zeit deutlich besser geworden). Diese Lösung ist nicht perfekt, aber vermutlich deutlich besser als frühere Workarounds. Genau wie beihtml2canvas: Wenn es zwingend nötig ist, ist es ein brauchbarer Ansatz.