HTML5 IN DER PRAXIS: RELAUNCH FÜR UNIVERSAL MUSIC

Transcrição

HTML5 IN DER PRAXIS: RELAUNCH FÜR UNIVERSAL MUSIC
HTML5 IN DER PRAXIS:
RELAUNCH FÜR
UNIVERSAL MUSIC
Wenn das größte Musiklabel der Welt seine mobile Präsenz einem Relaunch unterzieht, muss die
Lösung zukunftsweisend sein. Die neue mobile Webseite für die Universal Music Group (UMG) sollte
über responsives Design hinausgehen und die Performance für Mobilgeräte optimieren. VOTUM
übernahm die Entwicklung und Umsetzung. Das Ergebnis überzeugt mit einem zeitgemäßen
Designkonzept, ist mit allen gängigen mobilen Endgeräten nutzbar und verbessert mit einer
App-artigen Navigationsstruktur das Nutzererlebnis deutlich. Der Relaunch für die UMG: ein
Erfahrungsbericht zu aktuellen Webtechnologien.
Content First
Die Markup-Struktur der ausgelieferten Dokumente wurde unter Nutzung der HTML5 Outline
(Abschnitte eines Dokuments enthalten jeweils eine h1) komplett neu umgesetzt.
Derzeit evaluieren wir die tatsächliche Auswirkung auf Suchmaschinen und Screenreader bei
Nutzung der HTML5 Outline.
Fast alle Seitenfunktionen – außer der Suche, die nicht überarbeitet wurde – funktionieren
grundsätzlich auch ohne JavaScript (JS). So wurde die Seite mit Methoden der barrierearmen
Webentwicklung zugleich auch für Suchmaschinen optimiert. Aus Zeitgründen wurde bei diesem
Projekt dennoch auf eine vollständige Auszeichnung aller dynamischen Zustände via WAI-ARIA
verzichtet. Auch das Styling einer Ansicht mit deaktiviertem JavaScript wurde nur ansatzweise
umgesetzt, da eine Analyse des bisher aufgetretenen Webseiten-Traffics diese Aufwände nicht
rechtfertigen konnte.
Veranstaltungstermine wurden mit Microdata ausgezeichnet. Gerade bei Terminen ist die
Verwendung von Microdata schon derzeit sehr nützlich, da diese als Vorschau (zumindest bei
Google) auf den Suchergebnisseiten angezeigt werden. Weitere Inhaltstypen – wie Künstler oder
Musikvideos – wurden nicht durch Microdata betont, da hier der Nutzen noch nicht den Aufwand
rechtfertigt. Zumal für eine derart umfangreiche Webseite wie die der Universal Music GmbH
ein erheblicher redaktioneller Mehraufwand entstanden wäre, um z.B. Videos durchgängig und
vollständig mit Titel und Beschreibungen zu versehen.
Schnell und leicht:
Die Optimierung des Frontends
Der Fokus des Projekts lag auf der Performance-Optimierung des Webseiten-Frontends.
Das zugrunde liegende Framework wurde bereits in einem separaten Projekt optimiert und
außerdem durch einen Varnish-Cache entlastet. Im Frontend fanden wir eine gute Lösung
zwischen der festgelegten Minimalumsetzung und den Kundenwünschen. So ist zum Beispiel
die Startseite für eine mobile Ansicht immer noch sehr medienlastig. Um diese Fülle an Fotos
und Videos in optimierter Geschwindigkeit auszuliefern, haben wir die folgenden Schritte
unternommen.
2/11
1. Adaptive Images mit dem HTML5 PICTURE Tag
Zur Einbindung von Fotos (JPEG) wurden Adaptive Images über das HTML5 PICTURE Tag realisiert.
Hierbei werden je nach Layout-Breakpoint unterschiedlich große Dateien geladen. Da das
PICTURE Tag (noch) nicht von allen Browsern unterstützt wird, kommt picturefill.js von Scott Jehl
zum Einsatz. Ein Fallback auf die jeweils kleinste Variante eines Fotos wird in einem NOSCRIPT
eingebunden.
1a. Verwendete Größen
Wir mussten diverse Tests auf den tatsächlichen Endgeräten durchführen, um ein gut
ausbalanciertes Verhältnis von Ladezeit und Qualität des Bildmaterials zu erreichen. Folgende
Bildbreiten werden derzeit bei UMG für große Darstellungen (Header, Teaser) ausgeliefert.
Die Höhe der Medien richtet sich dabei jeweils nach dem Seitenverhältnis (z.B: 3:4, 16:9).
·
·
·
·
480px für Smartphones mit geringer Auflösung
720px für kleine Tablets und Smartphones mit höherer Auflösung
1020px für Tablets und kleine Desktops
1600px für hochauflösende Tablets und Desktops
Die Medien können außerdem abhängig von der Position unterschiedliche Größen haben (z.B.
Einsatz als Header-Bild oder in einem mehrspaltigem Raster). Um nun nicht für jede mögliche
Kombination aus Bildschirmauflösung und Spaltenanzahl Grafiken auf dem Server zu erzeugen,
wurde eine Liste mit erlaubten Zwischengrößen aufgestellt. Die Bilder wurden jeweils auf die
nächstgrößere Breite aufgerundet, somit muss der Browser Grafiken ggf. kleiner darstellen als
diese ausgeliefert wurden – jedoch werden niemals Bilder vergrößert und damit unscharf
gerendert.
Abb.: Screenshot der Website von Universal Music Group © Universal Music Group
3/11
<?php
$allowedSizes = array(
'160','240','300','380','480','550',
'720','1020','1200','1600' );
/**
* This function returns the closest matching width that is in the array
$allowedSizes.
*
* @param int $width
* @return int
*/
function getClosestSize( $width )
{
$closest = null;
foreach( self::$allowedSizes as $item )
{
if( is_null( $closest )
|| abs( $width - $closest ) > abs( $item - $width ) )
{
$closest = $item;
}
}
return $closest;
}
?>
1b. Generierung von Medien
Die Bilder werden erst bei der initialen Verwendung in den benötigten Größen generiert, wodurch
wir auf dem Server nicht alle UMG-Medien gleichzeitig erzeugen mussten. Da die Webseite mit
einem Varnish-Cache versehen wurde, sollten alle Medien als statische Resource genutzt werden.
Erst bei einem HTTP Status 404 innerhalb des Medienverzeichnisses ruft der Server das Skript zur
Generierung weiterer Bildgrößen auf.
2. Progressive Enhancement
Es gibt keine inline-Skripte und auf der mobilen Webseite existiert lediglich ein SCRIPT-Tag zur
Einbindung von RequireJS sowie der main.js zur Konfiguration und als Startskript.
Dadurch trennen wir Inhalt und Funktionalität. Einzelne Teile können in JS ersetzt werden,
ohne die Templates erneut zu überarbeiten.
Sämtliche interaktiven Funktionen (d.h. die dafür benötigten Skripte) werden erst geladen,
nachdem das Dokument und die Stile geladen wurden. Und dies auch nur, wenn sie wirklich
benötigt werden. Das heißt z.B., nur wenn ein Dokument ein Slider-Element enthält, wird auch das
Skript dazu geladen. Dadurch wird die scheinbare Ladegeschwindigkeit für den Nutzer erhöht.
AJAX-Funktionalitäten setzen auf einfachen HTML-Links auf.
4/11
Tracking-Funktionen wurden durch META-Tags (mit data-* Attributen), statt inline-JS, im Inhalt
umgesetzt. Dadurch ist in der Folge die Anpassung und Vereinheitlichung der nun ausgelagerten
Tracking-Skripte deutlich einfacher geworden.
JavaScript
Wir verwalten JavaScript als Module nach der Asynchronous Module Definition (AMD) und nutzen
RequireJS zum Laden der einzelnen Skriptdateien und zur Abhängigkeitsauflösung. Um zu
bestimmen, welche JS-Module geladen werden, setzen wir Selector Listener mit Bedingungen in
Form von CSS-Selektoren ein.
Modularer Aufbau der Skripte
Sämtliche Skripte sind modular in einzelnen Dateien organisiert (z.B. Nutzer, Slider, Tabs, …). AMD
hat sich in seiner einfachen Anwendung als nützliche Methode der Code-Strukturierung erwiesen.
Abhängigkeiten auf andere JS-Module werden automatisch aufgelöst und nachgeladen.
Bestehende Skripte wurden zum Teil lediglich in AMD Notation umformuliert.
Live Extensions & Conditional Loading
Wir setzen Page-Transitions ein, wobei ganze Seiten via XHR nachgeladen und via Slide-Effekt
eingeblendet werden. Dies bedingt, dass JS-Initialisierungsroutinen für einzelne Komponenten
nach dem AJAX-Load ausgeführt werden müssen. Um diesen Schritt nicht manuell ausführen zu
müssen, nutzen wir das moderne Konzept eines "Selector-Listeners". Hierzu werden keine EventHandler im üblichen Sinne eingesetzt, sondern es wird ein Event gefeuert, sobald ein bestimmter
Selektor (á la CSS) in der Seite erkannt wurde. Dadurch werden Initialisierungsskripte
automatisiert ausgeführt, wenn die entsprechende Komponente in die Seite eingefügt wurde.
Wir nutzen zur Umsetzung einen schlanken Custom-Build der Bibliothek better-dom. better-dom
ist derzeit nach unseren Tests die stabilste Lösung zur Umsetzung von Live Extensions. (Zum
Thema existiert im Smashing Magazine ein guter Artikel des Entwicklers Maksim Chemerisuk:
„Introducing Live Extensions For Better-DOM: What They Are And How They Work“). Allerdings ist
diese Bibliothek immer noch zu groß, da wir nur diese eine Funktionalität wirklich benötigen.
(Derzeit etwa ein Achtel von jQuery, also 12KB.) Bei mobilen Webseiten zählt jedoch jedes einzelne
Byte und kostet für den Nutzer unter Umständen sogar Geld. Was uns hier noch fehlt, ist ein
eigenständiges, schlankes JS Modul zur Umsetzung von Selector Listenern.
5/11
Abb.: Screenshot der Website von Universal Music Group © Universal Music Group
6/11
Asynchronität
Die Skripte werden asynchron geladen, um die gefühlte Ladegeschwindigkeit der Webseite zu
erhöhen, da die Dateien parallel herunter geladen werden können. Dadurch bedingt, ist die
Ladereihenfolge der Skripte nicht mehr festgelegt und die Entwickler müssen beim modularen
Aufbau bleiben, um Abhängigkeiten aufzulösen.
Moderne JS APIs
Bei diesem Projekt wurden in verstärktem Umfang moderne JavaScript APIs eingesetzt und die
Nutzung von jQuery erheblich reduziert. Damit konnte die Alltagstauglichkeit der modernen JS
APIs für den Produktivbetrieb getestet werden.
Auf der neuen mobilen Webseite wird keine Feature-Erkennung durchgeführt. Sollten einzelne
APIs durch einen Browser nicht unterstützt werden, wird die Funktionalität durch „Polyfills“
realisiert. Durch die Nutzung verschiedener Polyfills wäre sogar eine Kompatibilität bis hinunter
zum MS IE 8 möglich.
Der Hauptvorteil dieser Herangehensweise liegt in der verbesserten Performance des Frontends.
jQuery ist eine große Bibliothek, die auch noch relativ langsam läuft. Bei einigen Komponenten
wird jQuery gar nicht mehr geladen.
Ein Nachteil in der Verwendung von Polyfills ist die teilweise höhere Ladezeit aufgrund
zusätzlicher Skripte für ältere Browser. Dies haben wir jedoch bewusst in Kauf genommen.
Einige der eingesetzten APIs:
·
querySelector/querySelectorAll findet DOM Elemente mit einem CSS Selektor
· plainJS: var elem = document.querySelector('.panel > header')
·
classList vereinfacht die Arbeit mit CSS-Klassen
· plainJS: elem.classList.add('active')
·
dataset ermöglicht Zugriff auf HTML5 data-* Attribute
· plainJS: elem.dataset.theUserId, elem.dataset.theUserId = 1234
· Der MS IE hat Probleme beim Setzen von data-Attributen; hier muss ein Workaround
über setAttribute genutzt werden.
·
DOMParser ermöglicht das Parsen von Markup.
· plainJS: (new DOMParser()).parseFromString(htmlString, 'text/html')
· DOMParser wird von den meisten Browsern unterstützt – jedoch können einige
Browser (z.B. Safari) damit kein HTML parsen (XML jedoch schon). Daher ist ein
Polyfill hierfür nötig.
·
CustomEvent Einen eigenen Event-Typ nutzen wir bei der Synchronisierung der Media
Query Breakpoints.
· plainJS: var evt = new CustomEvent('deviceChanged', { state: 'xs' });,
window.dispatchEvent(deviceEvent);
7/11
·
CustomEvent wird auf älteren Versionen des nativen Android Browsers und
MS IE nicht unterstützt. Auch hier konnte erfolgreich mit einem Polyfill gearbeitet
werden.
Das Styling
Die Umsetzung wurde in LESS CSS auf Basis des Twitter Bootstrap realisiert, wobei letzteres als
Vorlage genutzt und zum Teil stark modifiziert wurde.
LESS
Die Unterseiten der Künstler und Genres unterscheiden sich in der Farbgebung. Die allgemeinen
Stylesheets wurden in eine CSS-Datei zusammengefasst und lediglich die Künstler-/GenreStylesheets separat erzeugt und für jede Unterseite ausgeliefert.
Media Query Breakpoints
In Anlehnung an Twitter Bootstrap wurde die mobile UMG Webseite mit vier Media Query
Breakpoints umgesetzt. Das heißt die Seite wird in vier Größenstufen an das jeweilige
Ausgabegerät angepasst. Diese Breakpoints wurden in einem iterativen Prozess mehrfach
implementiert (durch VOTUM & UMG) und im Verlauf von Tests noch oft angepasst. Auch wenn bei
der aktuellen UMG-Umsetzung letztlich nur vier Abstufungen genutzt wurden, stehen die Media
Queries mit sechs Stufen nun getestet zur Verfügung. Die entsprechenden Test-Dateien und CSS
Quellen wurden bei github.com veröffentlicht.
CSS Transitions und Animationen
Wo es möglich war, wurde für die Animation von Seitenelementen CSS genutzt. Die Effekte laufen
auf den meisten Geräten gut. Grundsätzlich sind CSS-Animationen empfehlenswert, da diese oft
flüssiger laufen als in JavaScript umgesetzte Animationen.
Allerdings haben wir die Erfahrung gemacht, dass CSS-Animationen (im Sinne von Transitions und
Animationen) sparsam eingesetzt werden sollten. Fünf Slider, ein Dropdown-Menü und andere,
überlagerte Animationen sowie überlappende, halbtransparente Bereiche führen zu erheblichen
Performance-Problemen auf Mobilgeräten. Die Leistung der Grafikkarten sowie der
Arbeitsspeicher sind im Gegensatz zu Desktop-Rechnern doch recht beschränkt.
Auf einigen Smartphones oder Browsern (z.B. HTC Desire 500, MS IE 10 auf Samsung Windows
Phone 8) haben wir sogar Browser-Abstürze beobachtet. Je nach Zielgerät sind Alpha-KanalManipulationen (opacity, rgba) sowie gleichzeitig ausgeführte Animationen sparsam einzusetzen.
Anwendungsbeispiele für CSS Transitions und -Animationen:
8/11
·
Page Transitions: Animation des Übergangs via Transition und Transform (transform:
translateX(100%))
·
Load Spinner: Icon-Drehung via Animation und Transform (transform: rotate(359deg))
·
pulsierende Tooltips via CSS-Animation
·
Dropdown: Ausklappen der Künstlermenüs via Transition (für height); da ein Übergang
zu height: auto; laut CSS-Spezifikation nicht möglich ist, muss hierbei vorher die
ursprüngliche Höhe der Dropdown-Box mit JS gesetzt werden.
Icon-Fonts
Alle Grafiken werden in einem Vektorformat genutzt und können daher in beliebigen Größen
dargestellt werden. Wir wollten ursprünglich direkt SVG-Dateien einbetten bzw. verknüpfen, leider
ist die Unterstützung für SVG gerade beim von Samsung verschlimmbesserten, nativen AndroidBrowser sehr mangelhaft.
Daher sind alle Icons und Logos als Icon-Webfont umgesetzt. Einfache Änderungen des
Erscheinungsbildes wie die Farbe, Umrandung oder ein Schatten wurden in CSS realisiert.
In Kombination mit CSS-Animationen setzen wir Font-Icons als Ersatz für ehemals animierte GIFs
ein (z.B. für das Lade-Symbol bei den XHR Page Transitions).
Synchronisierung der Media Query
Breakpoints von CSS nach JS
Da auch einige JS-Module auf unterschiedliche Breakpoints reagieren sollen, war es nötig, diese
Breakpoints auch in JavaScript zu definieren. Dadurch würde sich aber eine Redundanz der
Angaben ergeben, was erfahrungsgemäß irgendwann zu Fehlern führt. Daher haben wir eine
Methode erdacht und entwickelt, um die Media Queries nur in CSS durch den Browser zu rendern
und das Ergebnis in JS auszulesen.
Außerdem wollten wir an einigen Stellen nicht das resize Event nutzen, da dieses je nach Browser
unterschiedlich oft gefeuert wird. Die Skripte sollten ja nicht ausgeführt werden, wenn sich die
Bildschirmgröße ändert, sondern wenn ein neuer Breakpoint erreicht ist.
Das JS-Modul „Media Query Sync“ wurde bei github.com veröffentlicht.
9/11
Studieren geht über probieren:
viel Zeit fürs Testing
Der Aufwand für Tests war deutlich höher als geplant, da die Mobil-Browser nicht wie erwartet
technologisch homogen sind und Desktop- und Mobil Browser sich teilweise in der Darstellungsund Funktionsweise unterscheiden. Dies gilt insbesondere für den nativen Android-Browser sowie
für ältere Versionen des iOS Safari Browsers.
Schwierigkeiten bei der Umsetzung
Bedienbarkeit
Beim Zusammenspiel von verschiedenen Slidern auf einer Seite und Touch-Scrolling auf
Mobilgeräten traten einige Bedienprobleme auf. Teilweise wird ein Slider bewegt, obwohl der
Nutzer scrollen wollte und anders herum, da eine Fingerbewegung nie genau vertikal oder
horizontal ausgeführt wird.
Es kam auch zu konzeptuellen und technischen Problemen mit fix-positionierten Elementen auf
verschiedenen Mobilgeräten (position: fixed;). Diese Schwierigkeitene traten beim Zusammenspiel
von verschiedenen aufklappbaren Bereichen und statisch/fix positionierten Elementen auf. Bei der
Kombination von verschiedenen Interaktiven Bereichen sollte vorher ein Konzept aller möglichen
Animationen erstellt werden. Dies ist notwendig, um vorab die mögliche Kombination
verschiedener Zustände zu klären.
Herstellerspezifische Probleme
·
·
iOS Safari
·
Zoom-in bei Eingabefeldern, wenn die Schriftgröße kleiner als 16px ist.
· Fix: Schriftgröße bei :focus entsprechend groß setzen
·
Doppelklick auf Elemente mit :hover-Status notwendig.
· Fix: zusätzlich zu click-Event noch touchend-Event setzen, da der erste Klick im
iOS Safari für den :hover-Effekt genutzt wird.
·
virtuelle Tastatur wird nach Ajax-Submit nicht ausgeblendet
· Fix: das Eingabefeld darf beim Submit nicht mehr den Fokus haben,
document.getElementById(<element>).blur();
Android Native Browser (…something like Chromium)
· CSS Transformationen: Wenn der Browser-Zoom deaktiviert ist, hat der native
Android-Browser erhebliche Probleme mit 2D- und 3D-Verschiebungen. Die genaue
Fehlerursache konnte nicht ermittelt werden. (<meta name="viewport"
10/11
·
·
·
content="user-scalable=0" /> führt im Zusammenspiel mit transform: translate()
oder transform: translate3d() zu eigenartigen Vergrößerungseffekten der betroffenen
Elemente.)
Der native Android Browser hat Probleme damit, Element-Knoten aus anderen
Dokumenten einzubinden. Beispiel: Beim Parsen eines XHR Rückgabewertes als
HTML wird ein neues DOM Document erzeugt. Sollen nun Teile davon in die
bestehende Seite eingefügt werden, muss das betreffende Element vorher geklont
werden. (newDocument.appendChild(tagToInsert.cloneNode());)
CSS Generated Content: bei dynamisch durch CSS generierten Inhalten (PseudoElemente, Counter, u.ä.) wird der Inhalt u.U. nicht neu berechnet, wenn diese
Eigenschaft nachträglich gesetzt wird.
· Beispiel: <ol> mit CSS counter: counter-reset: item <integer>;. Bei einer
· Änderung des reset-Wertes, wird die Anzeige nicht neu gerendert.
· Fix/Workaround: CSS-Style direkt ins style-Attribut im HTML schreiben.
Microsoft Internet Explorer
· Image Replacement: Bei einigen IE-Versionen (leider ist keine verlässliche Liste
vorhanden, aber min. bis IE 10) kann die CSS Eigenschaft text-indent nicht
zuverlässig mit prozentualen Werten größer als 100 genutzt werden. Um einen
Textinhalt aus dem sichtbaren Bereich zu verschieben, sollte aus
Kompatibilitätsgründen immer ein vierstelliger, negativer Wert angegeben werden.
(z.B. text-indent: -9999px;)
Fazit
Viele moderne Eigenschaften von HTML5, JavaScript, CSS und anderen Web-Technologien sind
produktiv einsetzbar. Allerdings bedingen einige Anwendungen einen erhöhten Testaufwand. So
sind derzeit mehr unterschiedliche Browser im Einsatz als in den letzten zwanzig Jahren. Diese
Fragmentierung führt zu Kompatibilitätsproblemen, welche durch Entwickler entsprechend
bearbeitet werden müssen.
Außerdem bleibt anzumerken, dass Responsive Design allein nicht ausreicht, um eine gute mobile
Webseite zu erstellen. Moderne Webseiten müssen sich nicht nur für unterschiedliche
Ausgabegeräte eignen, sondern auch schnell laden. Und so müssen Webentwickler nach Jahren
des Verwöhnens durch Breitbandanschlüsse und Mehrkernprozessore nun wieder mit langsamen
Ladezeiten rechnen und auch Geräte mit geringer Rechenleistung berücksichtigen.
Ihr Ansprechpartner:
Bernd Alter
Head of Development
VOTUM GmbH
Ohlauer Straße 43
10999 Berlin
Tel.: +49 30 28 47 26 40 - 0
Fax: +49 30 28 47 26 40 - 75
[email protected]
www.votum.de
11/11