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