Neuerungen in HTML und CSS

Die Trends der Web-Frontends

Hendrik Ebbers

@shutterstock/Tashatuvango

Bei Webanwendungen hat sich nicht nur bei den Businessfeatures etwas getan, sondern auch im UI-Bereich. Responsive Design und der Support für Monitore mit hoher DPI-Zahl sind nur einige der Features, die eine moderne Webseite heute bieten sollte. Da viele der Features mit HTML und CSS-Bordmitteln nicht umgesetzt werden konnten, griff man in den letzten Jahren gerne auf Bibliotheken wie Bootstrap zurück. Doch HTML und CSS legen nach und bieten einige interessante neue Features für moderne UIs.

Ich denke, dass die meisten Entwickler mir zustimmen werden, wenn ich sage, dass Layout und Styling im Web keine einfache Aufgabe sind. Vor allem durch das Hinzukommen der Unterstützung für Mobile und Responsive Design ist die Aufgabe in den letzten Jahren nicht einfacher geworden. Zum Glück wurden hier einige CSS-Erweiterungen, wie Media Queries geschaffen, die verschiedene Layouts für unterschiedliche Ausgabegrößen und Geräte erlauben. Bibliotheken wie Bootstrap setzten bereits seit einiger Zeit genau auf diese Features, um responsive und konsistente UI-Toolkits bereitzustellen. Mit deren Komponenten und Layouts kann man einfach eigene Webanwendungen umsetzen. Aber sobald man begann, Bootstrap für die eigene Anwendung anzupassen oder zu erweitern, kam es oft zu Problemen. CSS-Klassen wurden doppelt genutzt, das gewünschte Layout funktionierte in bestimmten Konstellationen nicht mehr oder die Komplexität des CSS wurde extrem erhöht. Verschiedene neue HTML- und CSS-Features sollen in Zukunft helfen, genau diese Punkte besser zu machen. Dieser Artikel soll einige Neuheiten vorstellen, die 2016 interessant und wichtig für die Frontend-Entwicklung im Web werden könnten. Hierbei sollen allerdings keine hippen JavaScript-Frameworks im Vordergrund stehen. Vielmehr will ich auf einige neue Bestandteile der HTML und CSS Spec eingehen, die in den aktuellen oder folgenden Browserversionen von Haus aus jedem Entwickler und Designer zur Verfügung stehen werden.

Modularisierung und Komponenten

Eines der für mich wichtigsten Features in der modernen Webentwicklung ist die Modularisierung und Kapselung von Komponenten. Hierdurch ist es endlich möglich, echte wiederverwendbare Komponenten für das Web zu erstellen. Durch die Web-Component-Spezifizierung lässt sich dies bei modernen und zukünftigen Browserversionen auch komplett ohne ein externes Framework erreichen.

Als Beispiel der Vorteile einer Komponente soll die YouTube-Webseite herhalten. Schaut man sich die Startseite von YouTube an, kann man erkennen, dass das UI aus verschiedenen visuellen Komponenten zusammengesetzt ist. Schaut man nun allerdings in den Quellcode, kann man von diesen Komponenten leider nicht viel erkennen. Als Beispiel habe ich eine Vorschaubox genommen, von der mehrere auf der YouTube-Startseite und auch beim Abspielen eines Videos im rechten Bereich auftauchen. Abbildung 1 zeigt eine solche Vorschau.

Abb. 1: Eine Komponente der YouTube-Startseite ist die Vorschaubox

Abb. 1: Eine Komponente der YouTube-Startseite ist die Vorschaubox

Den kompletten HTML-Code dieser kleinen Box will ich dem Leser ersparen, da er rund eine Seite im Magazin einnehmen würde. Und hierbei spreche ich rein von dem Code zur Visualisierung der Komponente. Interaktion und Logik sind hierbei komplett außen vor. Daher zeigt Abbildung 2 den Code, um eine grobe Vorstellung über die Komplexität und (Un-)lesbarkeit des Quellcodes zu erhalten.

Abb. 2: Der Code zur Visualisierung der Vorschaubox ist komplex und schwer zu lesen

Abb. 2: Der Code zur Visualisierung der Vorschaubox ist komplex und schwer zu lesen

Schauen wir uns nun an, wie man das Ganze zum Beispiel mit einem UI-Toolkit realisieren könnte, das wiederverwendbare Komponenten nutzt. Wir verwenden JavaFX als UI-Technologie. Der folgende Quellcode geht davon aus, dass es die Klasse PreviewThumbnail als Custom UI Component gibt und die Klasse PreviewData als passendes Datenmodell. Die PreviewThumbnail-UI-Komponente weiß in diesem Fall, wie die in PreviewData definierten Daten gerendert werden sollen. Den Code zur Einbindung einer solchen Komponente:

PreviewData data = loadData();
PreviewThumbnail thumbnail = new PreviewThumbnail();
thumbnail.setData(data);
mainPanel.getChildren().add(thumbnail);

Geht man nun davon aus, dass die PreviewThumbnail-Komponente ein UI, wie das von YouTube, rendern kann, so ist der Anwendungsentwickler mit diesen paar Zeilen bereits fertig mit der Integration einer Thumbnail-Ansicht in eine View. Will man nicht mit einem spezialisierten Datenmodell arbeiten, kann man die GUI-Komponente auch so definieren, dass alle Attribute einzeln gesetzt werden können.

PreviewThumbnail thumbnail = new PreviewThumbnail();
thumbnail.setName(„Name of Video“);
thumbnail.setLink(„www.youtube.com/VIDEO_ID“);
thumbnail.setOwner(„Hendrik Ebbers“);
thumbnail.setOwnerLink(„www.youtube.com/channel/USER_ID“);
thumbnail.setViewCount(1638);
thumbnail.setCreationDate(…);
...
mainPanel.getChildren().add(thumbnail);

Natürlich soll hierbei nicht verheimlicht werden, dass innerhalb der PreviewThumbnail-Klasse beliebig komplexer Code zu finden sein kann. Der große Vorteil hierbei ist aber, dass dieser Code vor dem Anwendungsentwickler verborgen ist und somit der Aufbau von Views und Dialogen einfacher und leserlicher beschrieben werden kann. Eine komplette vertikale Liste von Vorschauelementen, wie man sie aus YouTube kennt, lässt sich hierdurch einfacher beschreiben. Nutzt man nun noch FXML zur Beschreibung von Layouts in JavaFX so würde die View wie folgt aussehen.

<VBox>
  <children>
    <PreviewThumbnail name="My Video" owner="Hendrik Ebbers" ... />
    <PreviewThumbnail name="Funny Cats" owner="Junior" ... />
    <PreviewThumbnail name="Minions 2 Trailer" owner="Franky" ... />
    <PreviewThumbnail name="Learn Java" owner="Nelly" ... />
    </children>
</VBox>

Spätestens jetzt kann man die Ähnlichkeit zu HTML sehen. Allerdings sieht der Aufbau sauberer aus und der Code lässt sich innerhalb kurzer Zeit lesen und verstehen. Der Grund hierfür ist, dass die Komplexität des Preview-Thumbnails innerhalb der Komponente gekapselt wird und von außen nicht ersichtlich ist. Durch setzen der Attribute bekommt die Komponente allerdings alle benötigten Informationen geliefert und kann so problemlos gerendert werden. Durch Webkomponenten lässt sich genau dieser Ansatz auch für Webanwendungen nutzen und ermöglicht so, dass auch bei komplexen Anwendungen HTML besser zu lesen ist und somit das Erweitern oder Umbauen einer Anwendung einfacher ausfällt.

Vier Spezifikationen für die Web Components

Zur Realisierung von Web Components wurde HTML um vier Spezifikationen erweitert: HTML Templates, Shadow DOM, Custom Elements und HTML Imports. Diese vier neuen Features erlauben es in Summe, dass sich wiederverwendbare Komponenten auch für Webseiten einfach realisieren lassen.

Mit HTML Templates ist es möglich, wiederverwendbares HTML zu definieren. Hierfür wurde der neue Tag <template> eingeführt. Innerhalb dieses Tags können beliebige HTML-Inhalte definiert werden, die dann durch JavaScript beliebig oft zum DOM hinzugefügt werden können. Hier die Definition eines Templates:

<template id="activity-template">
<div>

    <img class="icon" src="" width="40" height="40">
<div class="time"></div>
<div class=”content”></div>
</div>
</template>

Wird ein solches Template innerhalb einer HTML-Datei definiert, ist es im Browser erst einmal nicht zu sehen. Das Template kann aber in JavaScript referenziert und Kopien des Inhalts beliebig oft in das DOM kopiert werden.

var template = document.querySelector('#activity-template');
var clone = document.importNode(template.content, true);
document.body.appendChild(clone);

Hierdurch ist es zwar möglich, neue Elemente zu einem DOM hinzuzufügen, diese sind allerdings noch komplett statisch und verbessern die Lesbarkeit des Codes auch noch nicht wirklich. Wie aber bereits gesagt, werden alle vier Bestandteile der Web-Component-Spezifikation benötigt, um wirklich komplett wiederverwendbare und konfigurierbare eigene Komponenten zu entwickeln.

Daher schauen wir uns nun die zweite Spezifikation genauer an. Mit Shadow DOM ist es möglich, einen Bereich des DOM vor ungewollten Zugriffen zu schützen. Abbildung 3 zeigt das Beispiel für eine DOM-Hierarchie.

Abb. 3: Ein Beispiel für eine DOM-Hierarchie

Abb. 3: Ein Beispiel für eine DOM-Hierarchie

In diesem Beispiel soll der grüne Teil im rechten Bereich eine wiederverwendbare Komponente darstellen. Würde dessen Inhalt einfach als neue Subhierarchie an das vorhandene DOM gehängt, würden die Style Sheets der Anwendung den Inhalt der Komponente direkt beeinflussen. Dazu kommt, dass man Inhalte der Komponente einfach über JavaScript abfragen und mutieren könnte. In der Regel soll eine Komponente aber den Inhalt verbergen, um so die Komplexität zu verringern. Dazu kommt, dass ein Entwickler, der nichts über den Inhalt einer Komponente weiß, diese versehentlich durch CSS verändern könnte, indem er z. B. in der Anwendung die gleichen Style-Klassen benutzt wie interne Bestandteile der Komponente. In diesem Fall hat man ein Problem und müsste die CSS-Regeln wieder deutlich komplizierter definieren, um solche Konstellationen zu umgehen. Mit dem Shadow DOM kann man nun aber hergehen und einen Teil des DOM isolieren und von außen nicht mehr über die gängigen Wege zugänglich machen. Hierdurch kann man einzelne Komponenten in einer Sandbox definieren und es so zum Beispiel verhindern, dass CSS-Regeln auf das Styling der Komponente und deren interne Bestandteile durchschlagen. Hierbei wird, wie in Abbildung 4 gezeigt, der Inhalt der Komponente in eine neue Subhierarchie des DOM abgelegt, dem Shadow DOM.

Abb. 4: Der Inhalt der Komponente wird in einer neuen Subhierarchie des DOM abgelegt, dem Shadow DOM

Abb. 4: Der Inhalt der Komponente wird in einer neuen Subhierarchie des DOM abgelegt, dem Shadow DOM

Der Inhalt ist beim Rendern zwar voll sichtbar und wird auch im Browser angezeigt, CSS und JavaScript können aber nicht ohne Weiteres darauf zugreifen. Theoretisch kann man beliebigen Inhalt innerhalb eines Shadow DOM verbergen. Besonders interessant ist das Ganze aber, um eine Web Component zu kapseln. Durch ein JavaScript-Snippet wird ein neues Shadow DOM erstellt, das den Inhalt eines Templates füllt.

var root = host.createShadowRoot();
var clone = document.importNode(template.content, true);
root.appendChild(clone);

Die dritte benötigte Spezifikation zur Erstellung von Web Components sind die Custom Elements. Durch dieses Feature kann man neue Tags zur Nutzung in HTML definieren. So kann man einer Web Component eine eigenständige Bezeichnung geben. Wichtig ist hierbei, dass die Bezeichnung ein „-“ enthält, damit der Name nicht mit möglichen Standardtags kollidiert, die in Zukunft zu HTML hinzugefügt werden könnten. Durch Hinzufügen dieses dritten Features kommen wir den wiederverwendbaren Komponenten bereits deutlich näher, da es nun möglich ist, eine HTML View zu schreiben.

<div>
  <video-thumb name="video name" owner="Han Solo" ... />
  <video-thumb name="video name" owner="Luke Skywalker" ... />
  <video-thumb name="video name" owner="Anakin Skywalker" ... /></div>

Um das neue HTML-Tag zu registrieren, ist allerdings noch JavaScript-Code nötig. Listing 1 zeigt, wie ein Custom Element auf Basis eines Templates erstellt wird. Hierbei wird für jedes videothumb-Element im DOM das Template video-thumb-template geladen und innerhalb eines Shadow DOM an den DOM gehängt. Der Inhalt der beiden Attribute name und owner wird hierbei an innere Elemente weitergereicht.

var activityPrototype = Object.create(HTMLElement.prototype);

activityPrototype.createdCallback = function() {
var template = $("#video-thumb-template");
var clone = document.importNode(template.content, true);

var host = $(this);
$(".name", clone).text(host.attr("name"));
$(".owner", clone).text(host.attr("owner"));

var shadow = this.createShadowRoot();
shadow.appendChild(clone);
};
document.registerElement("video-thumb", {prototype: activityPrototype});

Somit können wir auf Basis von Templates, dem Shadow DOM und Custom Elements wirkliche wiederverwendbare Komponenten in HTML definieren, die wir beliebig oft auf einer HTML-Seite verwenden und auch durch Attribute konfigurieren können.

Um die Komponenten nun aber anwendungsweit oder auch über mehrere Applikationen nutzen zu können, werden noch die HTML Imports benötigt. Dieses Features erlaubt es, Bestandteile einer HTML-Datei auszulagern und diese einfach zu importieren. Definiert man so alle zu einer Web Component gehörenden Bestandteile – Definition des Templates und der JavaScript-Code zum Erstellen des Custom Elements – in einer eigenen HTML-Datei, so kann man diese leicht über einen link-Tag in jede beliebige andere HTML-Datei importieren.

	<link rel="import" href="components/video-thumb.html">

Schaut man sich die Verfügbarkeit dieser Features in aktuellen Browserversionen an (Kasten „Browsersupport“), so wird man sehen, dass die Hersteller hier noch viel nachliefern müssen. Allerdings gibt es ein Polyfill, das die Features bereits heute für alle gängigen Browserversionen nachliefert. Der Nutzung von Web Components steht also eigentlich nichts mehr im Weg.

Browsersupport

Noch nicht alle Browser unterstützen die vorgestellten Features. Tabelle 1 zeigt hierbei eine Übersicht alle beschriebenen Features und ihr Support in den gängigen Browsern. Eine grüne Zelle bedeutet, dass das Feature komplett von der aktuellen Version des Browsers unterstützt wird. Rot bedeutet, dass das Feature überhaupt nicht oder nicht vollständig unterstützt wird. In diesem Fall kann man auf Polyfills des jeweiligen Features zurückgreifen, falls diese vorhanden sind. Möchte man mehr zu weiteren Features erfahren oder den Support eines Features für eine spezielle Browserversion überprüfen, kann ich die Nutzung von http://caniuse.com empfehlen.

IE Edge Firefox Chrome Safari Opera
HTML Templates
Shadow DOM
Costum Elements
HTML Imports
FlexBox
Grid
CSS-Variable
Picture

Tabelle 1: Featureübersicht inklusive Browsersupport

CSS-Layouts: Elemente einfacher Positionieren

Ich denke, so ziemlich jeder Webentwickler hat schon geflucht, sobald es darum ging, eine Webseite mit CSS zu layouten. Hierbei ist nicht das Stylen von einzelnen Komponenten durch die Definition der Hintergrundfarbe oder Fontsize gemeint. Vielmehr geht es darum, die einzelnen Bestandteile einer Webseite zueinander auszurichten und zu positionieren. Das Ganze am besten natürlich noch unter Berücksichtigung von Responsive Design, sodass das Ergebnis auf allen Bildschirmauflösungen gut aussieht. Dies ist auf jeden Fall auch heute noch eine schwierige Aufgabe. Aber auch in diesem Bereich tut sich einiges. Hier stechen vor allem zwei neue CSS-Layouts hervor, die das Positionieren von Elementen in Zukunft einfacher gestalten sollen: Flexbox und Grid. Während Flexbox bereits seit einiger Zeit von so ziemlich allen wichtigen Browsern implementiert ist, steckt Grid noch in den Babyschuhen und läuft aktuell nur auf einem Nightly Build des Chrome-Browsers.

Flexbox punktet mit hoher Konfigurierbarkeit

Das CSS-Flexbox-Layout gibt es schon einige Zeit. Allerdings habe ich das Gefühl, dass es erst in der letzten Zeit wirklich bei den Entwicklern ankommt und genutzt wird. Das Layout ist durch seine hohe Konfigurierbarkeit extrem flexibel und ermöglicht es, verschiedene Darstellungen einfach umzusetzen. Bei den Layoutmöglichkeiten mag einem JavaFX-Entwickler folgender Vergleich helfen: Mit dem Flexbox-Layout lässt sich sehr einfach ein HBox-, VBox-oder Flow-Layout umsetzen. Initial ordnet das Layout einfach alle Kindelemente horizontal an. Eine vertikale Ausrichtung lässt sich durch die verschiedenen Properties der Flexbox ebenfalls konfigurieren. Gehen wir einmal davon aus, dass wir folgende HTML-Definition vorliegen haben.

<div class="parent">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>

Wie man sehen kann, gibt es ein Hauptelement mit der Style Class parent, das mehrere Kindelemente mit der Style Class item enthält. Setzt man nur ein paar Style-Informationen, um Font und Farbe der Komponenten anzupassen, so sieht das Ergebnis im Browser wie in Abbildung 5 aus.

Abb. 5: Das Ergebnis im Browser nach dem Setzen von Style-Informationen, um Font und Farbe anzupassen

Abb. 5: Das Ergebnis im Browser nach dem Setzen von Style-Informationen, um Font und Farbe anzupassen

Durch folgendes CSS kann nun einfach Flexbox als Layout für das Element definiert werden.

.parent {
  display: flex;
}

Das dazugehörige Ergebnis kann man in Abbildung 6 sehen.

Abb. 6: Mit Flexbox passen sich alle Kindelemente horizontal ihrem Elternelement an

Abb. 6: Mit Flexbox passen sich alle Kindelemente horizontal ihrem Elternelement an

Wie man sehen kann, passen sich nun alle Kindelemente durch Nutzung der Flexbox horizontal in ihrem Parent an. Hierbei füllen die Kindelemente den Parent im Idealfall bis zu ihrer Weite aus, werden allerdings nie größer als ihre definierte Weite. Ist dieses Verhalten nicht erwünscht, kann man durch Konfiguration der Flexbox einen automatischen Umbruch der Kindelemente definieren. Die Kindelemente nehmen in diesem Fall ihre definierte Weite an. Sobald ein neues Kindelement nicht mehr in den Parent passt, wird es in die folgende Zeile verschoben. Hierdurch ist es einfach möglich, ein flexibles Grid zu designen, wie man es aus Desktop- und Mobile-Anwendungen kennt. Das Ganze ist hierbei mit dem GridFX für JavaFX oder dem GridView in Android vergleichbar und eignet sich perfekt, um dynamische Listen von grafischen Elementen zu visualisieren. Um das Ganze umzusetzen, muss unser CSS angepasst werden.

.parent {
  display: flex;
  flex-wrap: wrap;
}

Die flex-wrap Property wird hierbei genutzt, um den Umbruch zu ermöglichen. Neben dem Standardwert nowrap und dem hier genutzten Wert wrap kann man die Property auch auf wrapreverse setzten, um so die automatischen Umbrüche nicht in die folgende Zeile nach unten, sondern nach oben durchzuführen. Abbildung 7 zeigt die Unterschiede.

Abb. 7: Automatische Umbrüche lassen sich einfach konfigurieren

Abb. 7: Automatische Umbrüche lassen sich einfach konfigurieren

Neben der Konfiguration der Hauptkomponenten kann man mit Flexbox auch das Layout einzelner Kindelemente konfigurieren. Als Beispiel sollen hier zusätzliche dieser CSS-Regeln genutzt werden.

.item:nth-child(2) {
  flex-grow: 1;
}
.item:nth-child(4) {
  order: -1;
}

Die flex-grow Property kann hierbei genutzt werden, um die Größenverhältnisse der Kindelemente zu beeinflussen. Der Wert definiert hierbei das Verhältnis der Komponenten zu den anderen Komponenten in der Flexbox. Da der Standardwert 0 ist, hat das zweite Kindelement – definiert durch nth-child(2) – mit einem flex-grow-Wert von 1 eine höhere Priorität beim Ausfüllen des vorhandenen Bereichs der Elternkomponente.

Über Definition der order Property kann man die Reihenfolge der Komponenten innerhalb der Flexbox beeinflussen. Auch hier ist 0 der Default-Wert. Und da ohne spezifische Definition der Property somit alle die gleiche Order haben, werden sie wie im HTML angegeben angeordnet. Im hier gezeigten CSS wird nun die order Property für das vierte Element auf -1 gesetzt, wodurch das Element eine geringere Order als alle anderen hat und somit vor den restlichen Komponenten angezeigt wird. Abbildung 8 zeigt das Ergebnis mit den neuen CSS-Regeln im Browser.

Abb. 8: Mit der „order“ Property lässt sich die Reihenfolge innerhalb der Flexbox beeinflussen

Abb. 8: Mit der „order“ Property lässt sich die Reihenfolge innerhalb der Flexbox beeinflussen

Neben den hier beschriebenen Konfigurationsmöglichkeiten bietet Flexbox noch deutlich mehr Optionen. So kann man das Basislayout von einer zeilenbasierten Ausrichtung in eine spaltenbasierte Ausrichtung umschalten. Durch zusätzliche Nutzung von Media Queries kann man so bereits sehr dynamische und responsive Layouts erstellen, die auch mit einer dynamischen Anzahl von Kindelementen gut umgehen können. Wer sich spielerisch mit den Möglichkeiten von FlexBox beschäftigen möchte, dem kann ich Flexbox Froggy empfehlen. Ansonsten gibt es online mittlerweile zahlreiche Dokumentationen und Videos, welche die verschiedenen Möglichkeiten der Flexbox aufzeigen. Flexbox wird zum Beispiel bei der Polymer-Paper-Komponentenbibliothek intern genutzt, um einfache Layouts von Anwendungen zu ermöglichen.

Grid teilt wirklich in Zeilen und Spalten

Eine weitere neue Möglichkeit für Layouting über CSS ist das Grid. Viele werden Grid-Layouts sicherlich bereits von Bibliotheken wie Bootstrap kennen. Allerdings hat das neue CSS-Grid-Modul wenig mit dieser Art von Layouts gemein. Das aus Bootstrap basierte Layout definiert eine spaltenbasierte Positionierung von Komponenten. Hierbei wird der zur Verfügung stehende Bereich z. B. in zwölf Spalten aufgeteilt. Und eine Komponente kann beliebig viele dieser Spalten in der Breite einnehmen. Die Höhe der Komponente wird durch das Layout nicht vorgegeben. Das neue CSS-Grid-Layout kann vielmehr mit einem Grid-Bag-Layout verglichen werden, wie man es z. B. aus Swing oder JavaFX kennt. Hierbei wird der zur Verfügung stehende Bereich in ein wirkliches Grid aus Zeilen und Spalten aufgeteilt. Die Komponenten werden nun innerhalb des Grids positioniert. Darüber hinaus gibt es noch mehr Unterschiede zu den aus Bootstrap und Co. bekannten Layouts: Musste man bei Bootstrap die Komponenten mit den durch Bootstrap definierten Style-Klassen versehen, um die Position festzulegen, kann man beim neuen Grid-Layout einfach die komplette Positionierung im CSS definieren. Im Folgenden gehen wir einmal davon aus, dass das HTML durch das Grid-Layout ausgerichtet werden soll.

<div class="wrapper">
<div class="header">...</div>
<div class="menu">...</div>
<div class="content">...</div>
<div class="footer">...</div>
</div>

Um das Grid nutzen zu können, muss man im Elternelement die display Property auf grid setzen. Nun kann man durch die beiden CSS Properties grid-template-columns und gridtemplate-rows ein Grid definieren. Die CSS-Regel für die Hauptkomponente ist:

.wrapper {
  display: grid;
  grid-template-columns: 120px 500px;
  grid-template-rows: 100px 400px 48px;
}

Das CCS spannt ein Grid über zwei Spalten und drei Zeilen auf. Hierbei werden für alle Spalten und Zeilen direkt die jeweiligen Größen angebenden. Hier ist es auch möglich, den auto-Wert anstelle eines fest definierten Werts für eine Spalte oder Zeile zu nutzen. Um das Grid nun zu füllen, müssen für die einzelnen Kindelemente ihre Position im Grid angegeben werden. Hierzu können die CSS Properties grid-column und grid-row genutzt werden. Diese definieren für jede Komponente, in welchen Zeilen oder Spalten sie positioniert werden soll. Die Dimensionen einer Komponente können hierbei problemlos über mehrere Spalten oder Zeilen aufgespannt werden. In diesem Fall definiert man die Startspalte (inklusive) und die Endspalte (exklusiv). Listing 2 zeigt, wie das CSS für das gezeigte Beispiel aussieht.

.header {
  grid-column: 1 / 3;
  grid-row: 1;
}

.menu {
  grid-column: 1;
  grid-row: 2;
}

.content {
  grid-column: 2;
  grid-row: 2;
}

.footer {
  grid-column: 1 / 3;
  grid-row: 3;
}

Abbildung 9 zeigt das Ergebnis des Layouts. Zur besseren Darstellung wurden hier noch ein paar zusätzliche Stylinginformationen definiert, wie Abstände oder die Hintergrundfarbe. Im hier gezeigten Beispiel definiert die Hauptkomponente ein Grid, und alle Kindelemente definieren per CSS-Regel, in welchen Zellen sie sich befinden.

Abb. 9: Mit Grid lässt sich die Dimension einer Komponente problemlos über mehrere Spalten oder Zeilen aufspannen

Abb. 9: Mit Grid lässt sich die Dimension einer Komponente problemlos über mehrere Spalten oder Zeilen aufspannen

Neben dieser Art der Konfiguration kann man die Positionierung von Kindelementen auch direkt in der CSS-Regel der Hauptkomponente definieren. Hierbei wird die grid-template-areas Property genutzt, die es ermöglicht, den Inhalt des Grids auf Basis beliebiger Komponentenbezeichnungen zu definieren. Durch die grid-area Property kann man in den CSS-Regeln den Kindelementen dann eine Bezeichnung zuweisen. Listing 3 zeigt, wie dies für das Beispiel aussehen würde.

.wrapper {
  display: grid;

    grid-template-columns: 200px 400px;
    grid-template-rows: 100px 400px 100px;
    grid-template-areas: "header header" "menu content" "footer footer";
}

.header {
  grid-area: header;
}

.menu {
  grid-area: menu;
}

.content {
  grid-area: content;
}

.footer {
  grid-area: footer;
}

Aktuell wird das CSS Grid leider von noch keinem Browser voll unterstützt. Nur der Chrome-Browser unterstützt das Grid aktuell als experimentelles Feature. Hierzu muss man „Experimental Web Platform Features Flag“ im Chrome aktivieren. Die Übersicht aller Feature-Flags von Chrome kann man erreichen, indem man chrome://flags/ im Chrome öffnet. Es gibt allerdings auch ein Polyfill des Features, das Grids bereits in aktuellen Browsern ermöglicht. Hier kann man eine Dokumentation des Grids mit verschiedenen Beispielen finden.

Bessere CSS-Struktur durch Variablen

Wenn man eine große Webanwendung oder sogar sein eigenes UI-Set für verschiedene Anwendungen entwickeln möchte, kommt es im CSS-Bereich oft zu Problemen bei der Wartbarkeit des Codes. Oft wird man in den CSS-Dateien die gleichen Informationen an verschiedenen Stellen finden. Wenn man z. B. ein spezielles Farbschema definiert, so muss die Basisfarbe für eigentlich jede Komponente gesetzt werden. Dies führt zu langen und unleserlichen CSS-Regeln. Möchte man das Farbschema nun ändern, kann man in der Regel nur mit „find and replace“ arbeiten, indem man den Farbwert von brown nach pink an allen Stellen im Style Sheet ändert. Dies ist einer der Gründe, warum CSS-Präprozessoren wie Less oder Sass die Nutzung von Variablen eingeführt haben. Dieses Feature wird nun auch für CSS spezifiziert, um auf der einen Seite Informationen an einer zentralen Stelle zu verwalten und es zusätzlich zu ermöglichen, eigene CSS Properties zu definieren. Die so definierten Properties eigenen sich besonders in Verbindung mit Webkomponenten. Da man so auf einfache Art und Weise Komponenten bauen kann, deren Stylingmöglichkeiten durch eigenständige Properties definiert werden können. Schauen wir uns das Beispiel von CSS-Variablen einmal genauer an.

.header {
  color: white;
  background-color: brown;
}
.content {
  color: brown;
}
.footer {
  background-color: brown;
}

Das gezeigte Beispiel könnte ein Ausschnitt aus einem CSS sein, das ähnlich wie Bootstrap einen kompletten und wiederverwendbaren Style für Anwendungen definiert. In diesem Fall kann man sehen, dass die Farbe Braun offenbar eine der Basisfarben dieses Themes ist. Würde man die Farben des Themes ändern wollen, so muss man beim gezeigten Beispiel alle Stellen suchen, in denen brown als Farbe gesetzt ist und diese abändern. Durch CSS-Variablen kann man die gewünschten Informationen in einer globalen Variable definieren. Alle weiteren Regeln greifen dann intern auf diese Variable zu. So muss man die spezifische Farbe nur noch an einer einzigen Stelle ändern.

:root {
  --main-bg-color: brown;
}
.header {
  color: white;
  background-color: var(--main-bg-color);
}
.content {
  color: var(--main-bg-color);
}
.footer {
  background-color: var(--main-bg-color);
}

In den gezeigten CSS-Regeln wird mit –main-bg-color bereits eine neue CSS Property definiert. Jede so definierte Property muss mit — beginnen. Der Support von Custom Properties eignet sich allerdings nicht nur, um globale Variablen, sondern auch, um Komponenten besser zu definieren. Im folgenden Beispiel soll ein Button mit einem Icon definiert werden. Hierzu wird nun auf Basis der Web-Component-Spezifikation eine eigenständige Komponente erstellt. Da für die Komponente das Icon immer die gleiche Farbe wie der Text des Buttons haben soll, könnte man die internen CSS-Regeln der Komponente wie folgt definieren.

.iconButton {
  background: var(--Button-backgroundColor);
  border: 1px solid var(--Button-foregroundColor);
  color: var(--Button-foregroundColor);
}

.iconButton .icon {
  --Button-color: var(--Button-foregroundColor);
}

Basierend auf diesem CSS müssen nur noch die Werte für –Button-foregroundColor und –Button-backgroundColor gesetzt werden, um die Komponente innerhalb einer Anwendung zu stylen. Da Custom Properties innerhalb des DOM vererbt werden können, ist es kein Problem, spezielle Styles für einen bestimmten Kontext zu definieren.

Modernes Arbeiten mit Images

Zuletzt möchte ich noch ein neues HTML-Element vorstellen, das den Weg in den HTML-Standard gefunden hat: das picture-Element. Mit diesem Element ist es möglich, einfach Bilder für verschiedene Devices und Auflösungen zu definieren. Durch Monitore mit immer höheren Auflösungen kam bei Webseiten schnell das Problem auf, dass Bilder entweder zu klein sind oder auf modernen Monitoren extrem verpixelt aussehen. Für die Retinadisplays von Apple gibt es daher auf vielen Webseiten alle genutzten Bilder in zwei Varianten: einmal für normale Displays und einmal für Retinadisplays. Bisher musste man für diesen Fall allerdings den Inhalt eines HTML-img-Elements händisch austauschen. Hierfür gibt es verschiedene JavaScript Libraries. Mit dem picture-Tag können nun aber einfach verschiedene Auflösungen für ein Bild hinterlegt werden. Listing 4 zeigt ein Beispiel, in dem das picture-Element genutzt wird. Hierbei wird nicht nur zwischen verschiedenen DPI unterschieden, sondern es werden auch basierend auf einer Media Query verschiedene Bilder abhängig von der Browsergröße gewählt. Hierdurch eignet sich das picture-Element auch ideal für Responsive Design.

<picture>

<source
  media="(max-width: 992px)"
  srcset="images/logo-mobile.png,
    images/logo-mobile@1.5x.png 1.5x,
    images/logo-mobile@2x.png 2x">
<img
  src="images/logo-desktop.png"
  srcset="images/logo-desktop@1.5x.png 1.5x,
    images/logo-desktop@2x.png 2x"
    alt="a cute kitten">
</picture>

Heutige Nutzung der Features

Wie man im Kasten Browsersupport sehen kann, werden viele der Features noch nicht von heutigen Browsern unterstützt. Für die meisten gibt es allerdings Polyfills, die es bereits heute erlauben, die Features zu nutzen. Polymer basiert z. B. auf einem Großteil der hier vorgestellten Features. Mit Polymer hat Google ein Framework zur einfachen Nutzung von Web Components entwickelt. Darüber hinaus bietet Polymer mit Polymer Paper eine komplette UI Library, die den Material-Design Style für das Web bereitstellt. Intern basiert Polymer auf den Spezifikationen für Web Components und stellt diese durch Nutzung von Polyfills bereits heute zur Verfügung. Die in Polymer Paper definierten Komponenten können bereits durch Nutzung von CSS-Variablen und Custom CSS Properties gestylt werden. So besitzt die Polymer Paper Toolbar die Property –paper-toolbar-background, die in einem externen CSS zum Anpassen und Stylen der Toolbar definiert werden kann. Gegenüber den hier beschriebenen Spezifikationen, die teilweise etwas komplex daher kommen, bietet Google Polymer ein darauf basierendes API, das die Entwicklung von Komponenten deutlich vereinfacht.

Aufmacherbild: Front-End Developer Vacancy in Newspaper von Shutterstock / Urheberrecht: Tashatuvango

Verwandte Themen:

Geschrieben von
Hendrik Ebbers
Hendrik Ebbers
Hendrik Ebbers (@hendrikEbbers) ist Java-Entwickler bei der Canoo Engineering AG. Sein Hauptinteresse liegt hierbei in den Bereichen JavaFX, User Interfaces und Middleware. Hendrik leitet die JUG Dortmund. Auf seiner Webseite www.guigarage.com bloggt er regelmäßig über Architekturansätze im Bereich JavaFX und zu seinen verschiedenen Open-Source-Projekten wie Dolphin Platform oder DataFX. Sein Buch "Mastering JavaFX 8 Controls" ist 2014 bei Oracle Press erschienen. Hendrik ist JavaOne Rockstar, Java Champion und JCP Expert Group Member.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: