Bei Warhol testen wir die Styles von Elementen direkt im Browser und Styles auslesen ist ein Performance-Albtraum sondergleichen. Ein Aufruf von getComputedStyle() löst Style-Neuberechnungen, möglicherweise gar Reflows aus und nicht bei jedem Element kommen wir mit einem einzigen getComputedStyle() aus – Pseudo-Elementen, :hover-States und vielen anderen Besonderheiten sei Dank. Warhol ist zwar dank allerlei Tricks und Optimierungen bei seinen Tests extrem flott unterwegs, aber noch schneller möchten wir natürlich trotzdem sein. Daher trieb mich zuletzt die Frage um, welche HTML-Elemente eigentlich immer und unter allen nur denkbaren Umständen unsichtbar bleiben. Könnten wir einem Element an seinem Tag und/oder seinen Attributen ansehen, dass es nichts rendern kann (und auch nicht durch z.B. Margins andere optische Auswirkungen haben kann), bräuchten wir seine Styles nicht abzufragen und hätten eine Menge Style-auslese-Operationen eingespart, womit ein großer Performance-Gewinn realisiert wäre – und je häufiger das Element, umso größer der Gewinn!

Sehr viele normalerweise unsichtbare Elemente sind lediglich per Browser-Standard-Styles auf display:none gesetzt. Elemente wie <style>, <script> sowie alle Elemente mit hidden-Attribut können ohne weiteres mittels display:block sichtbar gemacht werden, bei einem sichtbaren <title> ist zu beachten, dass auch der umgebende <head> sichtbar sein muss. Hier ist also kein Performance-Blumentopf zu gewinnen, denn wir können nicht einfach davon ausgehen, dass diese Elemente keine optischen Auswirkungen haben. Unwissenschaftlichen Twitter-Umfragen zufolge verwendet fast niemand sichtbaren <head>- oder <script>-Inhalt, aber fast niemand ist nun mal nicht niemand.

Elemente mit Inhalt, und seien es Scripts und Styles können also sichtbar werden. Wie ist es aber mit Elementen ohne Inhalt, wie z.B. <meta> oder <col>? Leider nicht wirklich anders! Zwar gibt es in diesen Elementen keinen Inhalt, der sichtbar gemacht werden könnte, aber mit einer Border werden auch leere Elemente sichtbar. Unter diese Definition von leer fällt auch das <template>-Element, dessen „Inhalt“ keine Auswirkungen auf das Rendering hat, für das sich aber neben Borders und Margins auch Pseudo-Elemente angeben lassen. Unsichtbar sieht definitiv anders aus.

Die nächste naheliegenden Kandidaten sind <br> und <wbr>. Die beiden Zeilenumbruch-Elemente widersetzen sich mit etwas mehr Vehemenz der Sichtbarmachung, haben aber eine Schwachstelle: die CSS-Eigenschaft content. Diese kennen wir vor allem aus der Arbeit mit den Pseudo-Elementen ::before und ::after, doch content kann noch mehr. Mit Text-Inhalt auf ein <br> angewendet verhilft die content-Eigenschaft in Chrome zumindest Margins zur Wirkung, in Firefox klappt das gleiche auch bei <wbr>. Damit haben die Elemente schon mal wahrnehmbare Auswirkungen, wenn sie selbst nicht sichtbar sind. Aber auch ihre Unsichtbarkeit lässt sich abschalten.

Text-Werte sind bei der Content-Eigenschaft nur für die Pseudo-Elemente ::before und ::after vorgesehen. Neben Texten akzeptiert die Eigenschaft aber auch url()-Werte und diese haben auch bei Nicht-Pseudo-Elementen einen Effekt: sie ersetzen den vorhandenen Inhalt durch etwas anderes und machen das Element quasi nachträglich zu einem Replaced Element. Replaced Elements sind Elemente, deren Inhalt nicht den Regeln von CSS unterliegt, da statt des Inhalts etwas anderes gerendert wird. In diese Kategorie fallen z.B. <video> und <img>, deren ganzer Zweck darin besteht, Platzhalter für Content aus externen Quellen (Videos und Bilder) zu spielen. So gesehen ist ein <span>-Element mit dem Text-Inhalt Foo, der per content: url(x.png) ersetzt wird, fast das gleiche wie ein <img alt="Foo" src="x.png">. Es versteht sich hoffentlich von selbst, dass solche Hacks unter keinen Umständen etwas in echten Web-Projekten zu suchen haben, denn sie widersprechen neben den Regeln von HTML-Semantik und Barrierefreiheit auch dem gesunden Entwicklerverstand. Ein Tool wie Warhol kann solche HTML/CSS-Fouls nicht ignorieren, aber jeder vernünftige Frontendler sollte das tun.

Unvernünftige Frontendler können zumindest in Chrome den (eigentlich nicht vorhandenen) Inhalt von zumindest <br>-Elementen per content ersetzen. Selbst Textumbrüche sind also bei entsprechendem CSS-Einsatz, der sie zu Replaced Elements macht, auch sichtbare Elemente.

Gibt es dann gar nichts, das wirklich per Definition unsichtbar ist? Doch, und zwar die folgenden Elemente:

  1. <audio>-Elemente ohne controls-Attribut §
  2. <input type="hidden"> §
  3. <noscript> wenn Scripting aktiviert ist §
  4. <form>-Elemente, die direkte Kinder von <table>, <thead>, <tbody>, <tfoot> oder <tr> sind (ohnehin kein gültiges HTML, aber technisch möglich) §
  5. Inhalte von Replaced Elements, d.h. <source> und <track> in <video> bzw. <audio>, Fallback-Inhalt in unterstützen <video>-, <audio>- und <canvas>-Elementen

Die ersten drei Punkte auf dieser Liste enthalten die einzigen Elemente, deren Browser-Standard-Styles die Deklaration display: none !important; enthalten (bzw. bei denen die Spezifikations-Prosa darauf schließen lässt) und nach den Regeln der Kaskade können diese Deklarationen durch nichts getoppt werden. Der letzte Punkt ist einerseits logisch (ersetzte Replaced Elements können nicht sichtbar sein), muss aber andererseits auch mit etwas Vorsicht genossen werden. Der Inhalt der genannten Elemente ist nur dann unsichtbar, wenn sie korrekt unterstützt werden, ansonsten dient der Inhalt als Fallback-Content für fossile Browser.

Außerdem erwähnenswert: das <picture>-Element ist kein Replaced Element, sondern dient nur als Steuerungs-Wrapper für das enthaltene <img>-Element. Entsprechend sind die <source>-Elemente in einem <picture> ohne größeren Aufwand sichtbar zu machen.

Wir halten fest: es gibt nur sehr wenige Elemente, bei denen Unsichtbarkeit sicher gegeben ist. Zu Beginn der Recherche hatte ich gehofft, Warhol könnte sich die Betrachtung von z.B. <br> grundsätzlich sparen, aber davon dürfen wir uns wohl verabschieden. Von den ewig unsichtbaren sind nur das <audio>-Element ohne controls und das <input type="hidden"> nicht an komplizierte Bedingungen geknüpft und von diesen beiden ist nur das letzte wirklich halbwegs häufig. Solange wir nur moderne Browser unterstützen mag es auch noch sinnvoll sein, den Inhalt von <audio>, <video>, <canvas> und <picture> zu ignorieren. Den großen Performance-Gewinn dürfte all das nicht einbringen, aber dann müssen wir uns den Gewinn eben anderswo holen.