CSS houdini
In ein paar Jahren könnte es möglich sein, neue CSS-Techniken sehr schnell einzusetzen. Und das sogar in allen Browsern.
Rendern unter Kontrolle
Eines der ambitioniertesten Projekte in der Welt der Webstandards ist CSS Houdini. Hinter dem Projekt steht die CSSTAG Houdini Task Force, deren Ziel es ist, „gemeinsam Features zu entwickeln, die die ‚Magie‘ von Styling und Layout im Web erklären“, heißt es im Wiki des Projekts. Konkret bedeutet das: Die Houdini Task Force arbeitet daran, Webstandards zu entwickeln, die es Entwicklern ermöglichen sollen, das Rendering einer Webseite in Browsern selbst zu beeinflussen. Dadurch könnte jeder Entwickler eigene Funktionen schreiben, die CSS einheitlich über verschiedene Browser hinweg darstellen. Aktuell können Entwickler zwar das HTML und CSS mit JavaScript beeinflussen, auf die eigentlichen Rendering-Prozesse haben sie aber keinen Zugriff. Die Browser kümmern sich im Hintergrund selbstständig um das Rendering einer Webseite. Das ist ein wenig wie Magie, daher auch der Name Houdini. Warum aber sollten Entwickler überhaupt in das Rendering einer Website eingreifen wollen? Schließlich funktioniert das Web bisher doch auch ohne diese Möglichkei- ten. Natürlich, irgendwie funktioniert es. Aber nicht ganz so komfortabel, wie es sein könnte. Denn es gibt viele moderne Techniken rund um CSS, die einige Browser bereits implementiert haben, andere aber nicht, oder nur teilweise. So bleibt Entwicklern in vielen Fällen nur die Möglichkeit, auf ein Feature erst einmal zu verzichten oder aber ein Polyfill zu nutzen, das versucht, ein Feature für ältere Browser zu emulieren (siehe Infokasten). Das bekannteste Beispiel ist hier sicher Flexbox, eine Layout-Technik für Webseiten, die 2009 zum ersten Mal vorgeschlagen wurde. Einsetzbar ist Flexbox aber erst seit etwa 2016 – je nachdem, welche Browserversionen in einem Projekt berücksichtigt werden mussten. Jahrelange Wartezeiten gab und gibt es auch für CSS Grids, CSS Variablen, Scroll Snap, position: sticky oder typografische Grundlinienraster. Jede Menge nützliche Techniken, bei denen Sie alle paar Monate erneut nachschlagen dür-
fen, welche Browser die Technik mittlerweile unterstützen; um dann erneut abzuwägen, ob es sinnvoll ist, die Technik in einem Projekt einzusetzen oder abzuwarten. Mit CSS Houdini wäre es irgendwann möglich, neue Techniken sehr viel schneller in aktuelle Projekte zu implementieren, zuverlässig über verschiedene Browser hinweg.
Die Phasen des Rendering-Prozesses bis zur Anzeige einer Webseite
Allerdings ist das Rendering einer Website eine komplexe Angelegenheit. Der Browser muss eine ganze Reihe von Schritten abarbeiten, bis die Seite angezeigt werden kann. Der Prozess lässt sich in die folgenden Schritte unterteilen. Parsing HTML: Zunächst analysiert der Browser das HTML-Dokument, erkennt die HTML-Elemente darin und bringt diese in eine Baumstruktur. Diese Struktur entspricht dem DOM (Document Object Model), in dem man ablesen kann, wie die Elemente ineinander verschachtelt sind. Dabei ignoriert der Parser Elemente, die er nicht kennt, und versucht selbstständig, kleine Fehler im HTML-Dokument zu korrigieren (etwa falsch verschachtelte Elemente). Parsing CSS: Ganz ähnlich läuft es beim CSS. Der Browser liest die CSS-Anweisungen ein und erstellt daraus eine analoge Baumstruktur, das CSSOM ( CSS Object Model). Ein Knotenpunkt enthält dabei alle Eigenschaften, die für diesen Selektor festgelegt wurden, aber auch all jene Eigenschaften, die es von höheren Elementen, etwa dem body, geerbt hat. Render Tree: Neben DOM und CSSOM wird noch eine weitere Baumstruktur angelegt: der Render Tree. Dieser Baum enthält visuelle Elemente in der Reihenfolge, in der sie später angezeigt werden sollen. Beim Firefox werden die Elemente in der Rendering-Struktur als Frames bezeichnet. WebKit verwendet den Ausdruck Renderer oder Render Object. Jeder Renderer steht für einen rechteckigen Bereich und enthält die entsprechenden CSS-Eigenschaften seines Knotens. Ein Renderer weiß damit, wie er sich und seine untergeordneten Elemente anordnet und darstellt. Die Struktur des Render Trees ähnelt dem DOM. Da es aber um visuelle Aspekte geht, werden HTMLElemente wie <head> nicht in den Render Tree aufgenommen. Ebenso enthält der Render Tree keine Elemente, die mit display: none versteckt wurden. Layout (Reflow): Bisher stehen die Renderer losgelöst für sich allein. Sie wissen noch nichts über ihre Position im Viewport oder ihre effektive Größe. In der Layout-Phase werden die Renderer nun im Viewport verteilt. Relative Maßangaben, wie Prozent, rem und em, werden in Pixel konvertiert und die exakten Positionen und Ausmaße der Elemente festgelegt. Das Layout ist ein rekursiver Prozess, das sich am Flusslayout-Modell von HTML orientiert. Er beginnt beim <html>-Element der Webseite. Elemente, die später im Fluss auftauchen, beeinflussen nicht unbedingt die Geometrie von Elementen, die früher im Fluss aufgetreten sind. So kann das Layout von links nach rechts und oben nach unten das Dokument durchlaufen. Dabei können man- che Elemente, wie etwa HTML-Tabellen, mehr als einen Durchlauf erfordern. Das Ergebnis der Layout-Phase ist das bekannte Box-Modell. Das HTML-Gerüst steht damit virtuell – es muss aber noch in Form von Pixeln auf den Bildschirm gemalt werden. Paint: Nun werden die einzelnen Elemente aufgebaut. Hier werden die tatsächlich Pixel gemalt für Hintergründe, Rahmen, Schatten, Texte etc. Compositing: Die einzelnen Teile werden nun noch richtig zueinander angeordet. Das kann wichtig sein, wenn Elemente übereinander liegen. Das Compositing wird machmal einzeln aufgeführt, manchmal aber auch mit Paint zusammengefasst. Dieser Prozess hört sich bereits recht komplex ist und ist doch nur eine vereinfachte Beschreibung, weil in den Browsern noch mehr vor sich geht und diese verschiedene Techniken anwenden, um Abläufe zu optimieren.
Wenn nun eine Änderung passiert, versuchen Browser möglichst wenig Arbeit zu investieren. Ändert sich die Farbe bei einem Element, kann sich der Browser darauf beschränken, nur dieses eine Element zu ändern. Wird hingegen der Viewport zusammengeschoben, müssen alle Elemente neu verteilt und gemalt werden. Die Developer Tools in modernen Browsern erlauben Ihnen, sich selbst ein Bild davon zu machen, wieviel Zeit für die einzelnen Schritte benötigt wird. In Chrome können Sie dazu in den DevTools im Reiter Performance eine Aufnahme starten, eine Webseite laden und dann die Aufnahme stoppen. In der Summary sehen Sie dann, wieviel Zeit etwa für Loading, Scripting, Rendering oder Painting benötigt wurde. Im Call Tree wird das weiter aufgeschlüsselt, und Sie können zum Beispiel die Zeiten für Parse HTML, Parse Stylesheet oder Update Layer Tree nachschlagen. Nun wird auch klarer, warum Polyfills nicht effizient sein können. Per JavaScript haben Entwickler nur die Möglichkeit, das HTML und CSS, und somit DOM und CCSOM, zu verändern. Das bedeutet in der Regel, dass der gesamte Rendering-Prozess neu angestoßen werden muss. Da das Polyfill aber dafür sorgt, dass der Browser Dinge macht, die er eigentlich nicht kann, muss das Polyfill-JavaScript erst einmal selbst das CSS parsen, verstehen, was der Benutzer will, dabei auch noch die Kaskade berücksichtigen und dann das HTML und CSS entsprechend anpassen. Das kostet Zeit.
Der aktuelle Stand der Houdini Drafts
Die Houdini-Arbeitsgruppe arbeitet deshalb an einer ganzen Reihe von APIs und Webstandards, mit denen es möglich sein soll, in die verschiedenen Phasen des beschriebenen Rendering-Prozesses einzugreifen. Zu den Houdini Editor Drafts gehören beim aktuellen Stand ( drafts.css-houdini.org): • Box Tree API • CSS Animation Worklet • CSS Layout API • CSS Painting API • CSS Parser API • CSS Properties and Values API • CSS Typed OM • Font Metrics API • Worklets Die ersten Drafts der Gruppe stammen aus dem Februar 2015, aber natürlich befinden sich alle Entwürfe immer noch in frühen Zuständen. Es wird ein paar Jahre dauern, bis diese Technik einsetzbar ist. Auf ishoudinireadyyet.com finden Sie einen Überblick zur Umsetzung der aktuellen Drafts in verschiedenen Browsern. Beim aktuellen Stand sind noch viele Felder rot (August 2018). Daran dürfte sich in den nächsten Monaten nichts ändern. Unter den Browsern ist Chrome weit vorne mit dabei und hat einige APIs bereits teilweise oder ganz umgesetzt. So können Sie etwa bereits die Paint API oder Typed OM (zur Umwandlung von CSS-Eigenschaften in typisierte JavaScript-Objekte) testen. Bei den Drafts ist die Paint API am weitesten fortgeschritten. Sie ist nicht nur in Chrome, sondern auch schon in Opera umgesetzt (beide nutzen Blink als Browser Engine). Und die zugehörige Spezifikation beim W3C hat den Status Candidate Recommendation. Daher schauen wir uns im Folgenden die Paint API etwas näher an.
Auf Paint API prüfen
Um das Beispiel oder andere Houdini-APIs selbst zu testen, benötigen Sie einen aktuellen Chrome Browser (ab Version 65). Dort müssen Sie zunächst chrome://flags über die Adresszeile aufrufen und die Experimental Web Platform F eatures einschalten. Beachten Sie außerdem, dass die Paint API nur über eine Website mit sicherer HTTPSVerbindung oder auf dem localhost funktioniert. Um zu überprüfen, ob ein beliebiger Browser überhaupt schon die Paint API unterstützt, können Sie das in JavaScript wie folgt prüfen: if ('paintWorklet' in CSS) {
// eigenes JavaScript }
In CSS wiederum können Sie dafür das Feature @supports nutzen: @supports (background: paint(id)) {
/* Paint API wird unterstützt */ }
Ein Schachbrettmuster malen
Als einfaches Beispiel nehmen wir eines aus Googles Web Fundamentals (bit.ly/ chromepaintapi). Dabei werden wir ein simples Schachbrettmuster in eine textarea malen. Die textarea nutzen wir nur, weil Sie diese in den Browsern per Default größer und kleiner ziehen können. Sie benötigen zwei Dateien. Zunächst die index.html: <!DOCTYPE HTML> <html> <head> <title>Test Paint API</title> <style> textarea { background-image: paint(checkerboard); } </style> </head> <body>
<textarea></textarea> <script> CSS.paintWorklet.
addModule('checkerboard.js'); </script> </body> </html> Diese HTML-Datei enthält als Inhalt nur eine textarea. Im Kopf der Datei wird die Paint API über das CSS der textarea angesprochen. Auf die id checkerboard beziehen wir uns später über JavaScript. Am Ende der Datei fügen wir ein Paint Worklet über die Datei checkerboard.js hinzu. Ein Worklet ist eine einfache Version eines Web Workers, der Entwicklern Zugang zu tieferen Ebenen der Rendering Pipeline gibt. Ein Paint Worklet bezieht sich auf die CSS Painting API und beschreibt, wie eigene CSS-Eigenschaften gerendert werden. Es gibt daneben auch Audio-, Animation- und LayoutWorklets. In unserem Fall enthält die checkerboard.js folgenden Code: class CheckerboardPainter { paint(ctx, geom, properties) { const colors = ['white', 'black']; const size = 40; for(let y = 0; y < geom.height/size; y++) { for(let x = 0; x < geom.width/size; x++) { const color = colors[(x + y) %
colors.length]; ctx.beginPath(); ctx.fillStyle = color; ctx.rect(x * size, y * size,
size, size); ctx.fill(); } } } } registerPaint('checkerboard',
CheckerboardPainter); Dadurch wird das „Hintergrundbild“der textarea durch das neue Worklet gefüllt bzw. ausgemalt. Der Code sorgt dafür, dass die zur Verfügung stehende Fläche in kleine Quadrate von 40x40 Pixel aufteilt wird. Mit den beiden for-Schleifen wird die Fläche in 40-Pixel-Schritten durchlaufen, jeweils ein Quadrat in der Größe 40x40 Pixel gemalt und abwechselnd mit einer der beiden Farben white und black gefüllt. Sie können die Zeile mit den Farben auch abändern und dort über zum Beispiel const colors = ['#E4572E', '# 17BEBB', '# 76B041',
'# FFC914']; dafür sorgen, dass das Muster vier farbenfrohere Farben enthält. Wenn Sie selbst mit dem Code experimentieren und keinen Unterschied sehen, müssen Sie den Cache im Browser deaktivieren. Worklets werden zunächst einmal automatisch vom Browser gecached. In Chrome können Sie dazu wieder die Developer Tools aufrufen. Im Reiter Network gibt es oben eine Checkbox Disable Cache. Sobald der Cache deaktiviert ist, erkennt der Browser auch Ihre Änderungen am Worklet. Mit Houdini’s CSS Paint Polyfill von Google Chrome Labs gibt es übrigens auch für die Paint API einen Polyfill, das die nötigen Paint Worklets und CSS Custom Paint in anderen modernen Browsern ermöglicht. Die entsprechende Demo läuft im Firefox überraschend flüssig, wenn auch nicht ganz so sauber wie im Chrome.
Weitere Beispiele
Mit den aktuellen Mitteln können Sie in Chrome bereits eine Menge anstellen. Das beschränkt sich nicht nur darauf, HTMLElemente auszumalen oder kleine Korrekturen am Rendering vorzunehmen. Sie können über die Methode CSS.registerProperty() auch eigene CSS-Eigenschaften definieren und dann die Darstellung programmieren (bit.ly/registerProperty). Auf css-houdini. rocks finden Sie weitere CSS-Houdini-Experimente vom Designer und Webentwickler Vincent De Oliveira. Am Ende wird es aber gar nicht nötig sein, dass sich jeder Webworker seine eigenen Worklets schreibt. Sobald alle modernen Browser die Houdini-APIs unterstützen, dürften sich recht schnell ein paar Frameworks durchsetzen, die jene Features, auf die Webworker schon länger warten, endlich in alle Browser bringen. Das lässt doch auf die Zukunft hoffen. Auch wenn es noch ein paar Jahre dauern wird, bis die Houdini Drafts ausgereift und in allen Browsern angekommen sind.