Nach gar nicht mal so langem Sammeln von Leserfragen musste ich diesmal sehr lange schreiben um die teilweise ausgesprochen kniffligen Fragen zu beantworten. Aber es ist geschafft! Und falls ihr meint, dass ihr für den nächsten Teil dieser Serie noch schwierigere Fragen auf Lager habt, schreibt sie mir per E-Mail oder gebt die Frage per Twitter ab.

HTML5 File APIs

Kann man mit der HTML5 File API Verzeichnisse auf dem Client auslesen?

Die File API definiert nur Funktionen, die mit Datei-Objekten im Browser arbeiten, aber dort ist kein Mechanismus festgehalten, wie diese Dateien in den Browser gelangen. Aktuellen Standards zufolge gibt es hierfür folgende Möglichkeiten:

  • Drag & Drop
  • Input-Elemente mit type="file" (DOM-Eigenschaft files)
  • Scripts, die selbst mit dem Blob-Constructor Datei-Objekte erzeugen

Das Auslesen eines Verzeichnisses ist nicht dabei. Die File System API sollte etwas derartiges ermöglichen, ist allerdings aktuell nur in Browsern mit Blink-Engine (Chrome und Opera) zu finden und wird vom W3C auch nicht mehr als Standard weiterentwickelt. Für den Fall, dass man dringend in einer Webapp ein simuliertes Dateisystem braucht, wird allgemein empfohlen, ein solches auf Basis von Indexed DB (die Blobs speichern kann) selbst zu bauen.

hgroup-Element - tot oder lebendig?

Ich versuche gerade mir HTML5 und CSS3 anhand deines Videotrainings von 2011 beizubringen. Ich bin dabei auf das <hgroup>-Element gestoßen, das laut einigen Meldungen seit Mitte letzten Jahres nicht mehr gültig sein soll. Auch du bestätigst diese Aussage auf deiner Webseite im August 2013, obgleich das Element auch heute noch – also ca. ein Jahr später – in den Spezifikationen der WHATWG auftaucht. Meine Fragen:

  1. Existiert <hgroup> nun endgültig nicht mehr oder ist sein Status weiterhin ungeklärt? Klar, kaum jemand benutzt es und deshalb kann von einer Nicht-Existenz gesprochen werden, aber ist es auch offiziell?
  2. Im Netz geistern die Alternativen zu <hgroup> herum. Inwiefern sind diese aktuell, bzw. offiziell?
  3. Wie gehst du in HTML mit auftauchenden Untertiteln, Zusatztiteln etc. um?

Das ist ausgesprochen kompliziert.

  1. Die Frage an dieser Stelle ist, was bei semantischen Elementen „Existenz“ ausmacht. Wie du richtig sagtest steht <hgroup> weiterhin in den Spezifikationen der WHATWG, fehlt aber beim W3C. Die Browser unterstützen meinen Tests zufolge das Element auch insofern, als dass es zumindest oberflächlich betrachtet implementiert ist (document.createElement('hgroup').toString() !== '[object HTMLUnknownElement]'). Andererseits macht das Element nur im Kontext des Outline-Algorithmus richtig viel Sinn und dass dieser Algorithmus ein reiner Papiertiger ist, ist eigentlich Konsens. Wenn man das Element in eine Webseite einbaut, macht es nichts. Man könnte also sagen, dass das Element zwar da ist, aber eigentlich nicht wirklich zu etwas gut ist. Das <hgroup>-Element ist Stand Mitte 2014 der Blinddarm von HTML5.
  2. Es gibt keinen in Stein gemeißelten 1:1-Ersatz. Die Spezifikationen von W3C und WHATWG haben je einen Abschnitt "Common idioms without dedicated elements" in dem es beim W3C auch Empfehlungen zu Untertiteln und derartigem abgibt. Das sind allerdings auch nur Vorschläge, denen man folgen kann, aber nicht muss.
  3. Ich persönlich folge den W3C-Empfehlungen, gruppiere also Überschriften mit Untertiteln usw. in <header>-Elementen, wobei die Untertitel keine Überschriften-Elemente, sondern irgend etwas anderes sind. Ich mache das nicht, weil es das W3C so empfiehlt, sondern weil die dortigen Vorschläge meiner Meinung nach einfach eine sehr gute Lösung darstellen. Würde man <hgroup> verwenden, wäre das eine (recht riskante) Wette darauf, dass sich dieses Element im Laufe der Zeit doch noch durchsetzt. Im Vergleich zu z.B. einem <header>-Element gibt es bzgl. Lesbarkeit des Quelltextes, Barrierefreiheit oder Browserunterstützung keinen Vorteil für <hgroup>. Der einzige Unterschied liegt in der Behandlung der enthaltenen Überschriften unter den Bedingungen des Outline-Algorithmus, der, wie erwähnt, keine Rolle spielt. Alles in allem: man könnte <hgroup> zwar benutzen ohne größere Katastrophen auszulösen, aber man hat nichts davon und geht dafür das Risiko ein, in Zukunft ein ungültiges Dokument haben (ohne dass die dann bestehende Ungültigkeit irgendwelche negativen Folgen hätte, denn jeder Browser auf diesem Planeten würde es ohne zu klagen verarbeiten).

Zwei zusätzliche Anmerkungen möchte ich zu diese Fragen noch loswerden. Erstens: Webstandards sind keine Wissenschaft. Der Prozess, in dem neue Regeln entstehen, ist unübersichtlich und obwohl es im Prinzip Regeln für den Prozess gibt, ist das Dehnen dieser Regeln an der Tagesordnung. Wird dann irgendwann mal eine neue definitive Regel aufgeschrieben, ist immer noch nicht auszuschließen, dass kurze Zeit später wieder die Kehrtwende kommt. Oder es kann passieren, dass das, was aufgeschrieben irgendwo steht, aus guten Gründen ignoriert wird. Es ist in letzter Konsequenz Politik.

Zweitens: „Offiziell“ ist überbewertet. Eigentlich ist etwas „offiziell“ ist etwas, sobald ein Dokument ein fertiger Webstandard (Recommendation) ist. Das allein muss aber auf die gelebte Praxis nicht unbedingt Auswirkungen haben. So war z.B. CSS 2 lange Zeit Recommendation, wurde aber dann effektiv zurückgezogen, weil sich kein Browser an das hielt, was in dem Dokument stand. Ein wie auch immer gearteter „offizieller“ Status ist nicht so wichtig wie die Frage, ob ein Feature funktioniert und sinnvolle Dinge ermöglicht. Ich würde behaupten, dass <hgroup> nicht offiziell existiert (auch wenn auch nicht explizit abgeschafft ist), nicht funktioniert (es macht in Browsern schließlich nichts) und sinnvolle Dinge ermöglicht es auch nicht. Also weg damit!

Text messen ohne Browser

Wie kann man in Node.js herausfinden, welche Abmessungen ein Text bei einer bestimmten Schriftgröße mit einer bestimmten Schriftart hat? Wenn möglich ohne einen headless browser wie PhantomJS o.Ä. bemühen zu müssen …

Auch hier hilft, man glaubt es kaum, HTML5! Das Canvas-Element bietet eine Funktion, die genau das Gewünschte macht: measureText(x) nimmt einen Text x und schaut nach, welche Ausmaße er bei den aktuellen Schrift-Settings hat. Und natürlich gibt es eine Canvas-Implementierung für Node.js. Diese ist zwar wegen diverser Abhängigkeiten nicht ganz so einfach zu installieren wie die meisten anderen Node-Module, aber wenn das geschafft ist, kann man ganz normalen Canvas-Code zum Textvermessen schreiben …

var Canvas = require('canvas');
var canvas = new Canvas(200, 200);
var ctx = canvas.getContext('2d');

// Schrift-Einstellungen
ctx.font = 'bold 16px Georgia';

// Text ausmessen
var textMetrics = ctx.measureText('Wie breit wird das hier?');

console.log(textMetrics);

 … und ihn in Node ausführen:

$ node node-canvas.js 
> { width: 199,
    actualBoundingBoxLeft: 1,
    actualBoundingBoxRight: 198,
    actualBoundingBoxAscent: 12,
    actualBoundingBoxDescent: 1,
    emHeightAscent: 15,
    emHeightDescent: 4,
    alphabeticBaseline: 0 }

Kein PhantomJS, keine ungewöhnlichen APIs: es geht einfach!

CSS und Shadow DOM

Wie verhält es sich mit Styles und JavaScript im Zusammenspiel mit Shadow DOM? Muss davon ausgegangen werden, dass Styles und Scripts aus dem Haupt-Dokument in das Shadow DOM von Web Component überschwappen und dort dann recht umfangreiche Resets nötig werden?

Das ist eine nicht ganz einfach zu beantwortende Frage. Vor allem darf man nicht vergessen, dass Shadow DOM noch eine sehr experimentelle Technologie ist und Änderungen durchaus im Bereich des möglichen sind. Entsprechend vorsichtig sollten die folgenden Aussagen behandelt werden.

Grundsätzlich ist die Antwort auf die Frage ein ganz klares Jain. Einerseits liegt um einen Shadow-DOM-Baum eine Grenze. Diese Grenze kann nicht von Selektoren (CSS oder JavaScript) überschritten werden. Befindet sich im Eltern-Dokument eine Style-Regel für z.B. <h1>-Elemente, wird diese Regel nur die Elemente betreffen, die direkt im Dokument stehen – eventuell in Shadow DOM vorhandene <h1>-Elemente bekommen von dieser Regel nichts mit. Umgekehrt sind in einem Shadow Tree definierte Styles auch nur innerhalb dieses Shadow Trees gültig und beeinflussen das Dokument, in das der Tree eingebunden ist, nicht.

Andererseits unterliegen mit einem Shadow DOM ausgestattete Elemente den Regeln der ganz normalen CSS-Vererbung. Gibt es in einem Shadow Tree beispielsweise keine Festlegung auf eine Schriftfarbe, so wird die Schriftfarbe verwendet, die das Elternelement des Shadow Trees hat. Ein kombiniertes Beispiel für beide Fälle könnte so aussehen:

<!doctype html>
<meta charset="utf-8">
<title>Shadow DOM</title>
<style>
  body {
    color: red;
  }
  span {
    font-weight: bold;
  }
</style>

<p>Im nächsten Element steht <span>Shadow DOM</span></p>
<p>Wenn du das hier lesen kannst, kann dein Browser kein Shadow DOM</p>

<script>
  var shadowHost = document.querySelectorAll('p').item(1);
  var shadowRoot = shadowHost.createShadowRoot();
  var content = '<style>span { letter-spacing: .5em; }</style>' +
                'Hallo <span>Welt!</span>';
  shadowRoot.innerHTML = content;
</script>

In einem Browser, der Shadow DOM korrekt umsetzt (z.B. Chrome 37) sollte das Ergebnis wie folgt aussehen:

Das Erscheinungsbild ergibt sich wie folgt:

  1. Der Text ist überall rot, auch im Shadow DOM, da diese Regel vom <body>-Element weitervererbt wird und das Shadow DOM keine eigene Schriftfarbe festlegt
  2. Nur <span>-Elemente außerhalb des Shadow DOM werden fett, da der Selektor nicht die Grenze zwischen Elterndokument und Shadow DOM überschreiten kann
  3. Nur das <span>-Element im Shadow DOM ist von der letter-spacing-Deklaration betroffen, da auch hier der Selektor an der Grenze hängen bleibt
  4. Fragt man mit JavaScript alle <span>-Elemente im Dokument ab, so wird nur ein einziges zurückgegeben – das Element außerhalb des Shadow DOM.

Zwischenzeitlich waren einige weitere Möglichkeiten geplant, um Einfluss auf die CSS-Balance zwischen Elterndokument und Shadow DOM zu nehmen. So sollte es einen Vererbungs-Reset für Shadow Trees geben, was in unserem Beispiel keine rote Farbe im Shadow DOM zur Folge hätte. Außerdem stand auch mal die Einführung eines Flags zur Diskussion, das CSS-Regeln aus dem Elternelement in das Shadow DOM durchgelassen hätte. Aktuell sind beide Features weder im neuesten Spezifikationsdraft noch in irgendwelchen Browsern zu finden.

Weitere Fragen?

Weitere Fragen zu HTML5, JavaScript und anderen Webtechnologien beantworte ich natürlich gerne! Sendet mir eure Fragen einfach per E-Mail oder Tweet und ich antworte so schnell ich kann. Und ansonsten kann man mich natürlich auch als Erklärbär zu sich kommen lassen.