Medienabfragen sind toll, aber…
Mediaabfragen sind großartig, ein Segen für Websiteentwickler, die kleine Anpassungen an ihren Stylesheets vornehmen möchten, um die Nutzerfreundlichkeit auf Geräten verschiedener Größe zu verbessern. Mit Medienabfragen können Sie das CSS Ihrer Website je nach Bildschirmgröße anpassen. Bevor Sie diesen Artikel lesen, sollten Sie sich mit responsivem Design vertraut machen und sich einige gute Beispiele für die Verwendung von Medienabfragen ansehen: mediaqueri.es.
Wie Brad Frost in einem früheren Artikel betont, ist das Ändern des Erscheinungsbildes nur eine von vielen Dingen, die beim Entwickeln für das mobile Web berücksichtigt werden müssen. Wenn Sie beim Erstellen Ihrer mobilen Website nur Ihr Layout mit Media-Abfragen anpassen, ergibt sich folgende Situation:
- Alle Geräte erhalten dasselbe JavaScript, CSS und Assets (Bilder, Videos), was zu längeren Ladezeiten führt.
- Alle Geräte erhalten dasselbe initiale DOM, was Entwickler möglicherweise dazu zwingt, übermäßig kompliziertes CSS zu schreiben.
- Wenig Flexibilität bei der Angabe benutzerdefinierter Interaktionen, die auf jedes Gerät zugeschnitten sind.
Web-Apps benötigen mehr als Medienabfragen
Verstehen Sie mich nicht falsch. Ich mag responsives Design über Media-Queries und finde, dass es einen Platz in der Welt hat. Außerdem lassen sich einige der oben genannten Probleme mithilfe von Ansätzen wie responsiven Bildern oder dem dynamischen Laden von Scripts beheben. Irgendwann werden Sie jedoch feststellen, dass Sie zu viele inkrementelle Optimierungen vornehmen, und es ist besser, unterschiedliche Versionen bereitzustellen.
Wenn die von Ihnen erstellten Benutzeroberflächen komplexer werden und Sie sich für One-Page-Webanwendungen entscheiden, sollten Sie die Benutzeroberflächen für jeden Gerätetyp anpassen. In diesem Artikel erfahren Sie, wie Sie diese Anpassungen mit minimalem Aufwand vornehmen. Der allgemeine Ansatz besteht darin, das Gerät des Besuchers in die richtige Geräteklasse einzuteilen und die entsprechende Version für dieses Gerät bereitzustellen, wobei die Codewiederverwendung zwischen den Versionen maximiert wird.
Auf welche Geräteklassen möchten Sie Ihre Anzeigen ausrichten?
Es gibt unzählige internetfähige Geräte und fast alle haben Browser. Die Herausforderung liegt in ihrer Vielfalt: Mac-Laptops, Windows-Arbeitsstationen, iPhones, iPads, Android-Smartphones mit Touchbedienung, Scrollräder, Tastaturen, Sprachbedienung, Geräte mit Druckempfindlichkeit, Smartwatches, Toaster und Kühlschränke und vieles mehr. Einige dieser Geräte sind allgegenwärtig, andere sehr selten.
Um eine gute Nutzererfahrung zu schaffen, müssen Sie wissen, wer Ihre Nutzer sind und welche Geräte sie verwenden. Wenn Sie eine Benutzeroberfläche für einen Desktop-Nutzer mit Maus und Tastatur erstellen und sie einem Smartphone-Nutzer geben, ist Ihre Benutzeroberfläche frustrierend, da sie für eine andere Bildschirmgröße und eine andere Eingabemethode konzipiert ist.
Es gibt zwei Extreme:
Eine Version erstellen, die auf allen Geräten funktioniert Die UX leidet darunter, da unterschiedliche Geräte unterschiedliche Designüberlegungen erfordern.
Erstellen Sie eine Version für jedes Gerät, das Sie unterstützen möchten. Das dauert ewig, weil Sie zu viele Versionen Ihrer Anwendung erstellen. Wenn das nächste neue Smartphone auf den Markt kommt (was ungefähr wöchentlich passiert), müssen Sie außerdem noch eine weitere Version erstellen.
Hier gibt es einen grundlegenden Kompromiss: Je mehr Gerätekategorien Sie haben, desto besser ist die Nutzererfahrung, aber desto mehr Arbeit ist für die Entwicklung, Implementierung und Wartung erforderlich.
Das Erstellen einer separaten Version für jede ausgewählte Geräteklasse kann aus Leistungsgründen oder wenn die Versionen, die Sie für verschiedene Geräteklassen bereitstellen möchten, stark variieren, eine gute Idee sein. Andernfalls ist responsives Webdesign ein durchaus sinnvoller Ansatz.
Eine mögliche Lösung
Hier ist ein Kompromiss: Klassifizieren Sie Geräte in Kategorien und entwickeln Sie für jede Kategorie die bestmögliche User Experience. Welche Kategorien Sie auswählen, hängt von Ihrem Produkt und Ihrer Zielgruppe ab. Hier ist eine Beispielklassifizierung, die die beliebten webfähigen Geräte abdeckt, die es heute gibt.
- Kleine Bildschirme + Touchbedienung (meist Smartphones)
- Große Bildschirme + Touchbedienung (meist Tablets)
- Große Bildschirme + Tastatur/Maus (meist Desktop-Computer/Laptops)
Dies ist nur eine von vielen möglichen Aufschlüsselungen, die aber zum Zeitpunkt der Erstellung sehr sinnvoll ist. In der Liste oben fehlen Mobilgeräte ohne Touchscreen (z. B. Smartphones, einige E-Book-Reader). Die meisten dieser Geräte haben jedoch eine Tastaturnavigation oder Screenreader-Software installiert, die gut funktioniert, wenn Sie Ihre Website barrierefrei gestalten.
Beispiele für formfaktorspezifische Web-Apps
Es gibt viele Beispiele für Web-Properties, die für unterschiedliche Formfaktoren völlig unterschiedliche Versionen bereitstellen. Das ist bei der Google Suche und bei Facebook der Fall. Dabei geht es sowohl um die Leistung (Abrufen von Assets, Rendern von Seiten) als auch um die allgemeine Nutzerfreundlichkeit.
Bei nativen Apps passen viele Entwickler ihre App an eine Geräteklasse an. Beispielsweise hat Flipboard für das iPad eine ganz andere Benutzeroberfläche als Flipboard auf dem iPhone. Die Tabletversion ist für die Nutzung mit zwei Händen und das horizontale Drehen optimiert, während die Smartphoneversion für die Nutzung mit einer Hand und das vertikale Drehen gedacht ist. Viele andere iOS-Apps bieten auch deutlich unterschiedliche Smartphone- und Tabletversionen, z. B. Things (To-do-Liste) und Showyou (soziale Videos), die unten gezeigt werden:
Methode 1: Serverseitige Erkennung
Auf dem Server haben wir nur sehr begrenzte Informationen zum Gerät, mit dem wir es zu tun haben. Der wahrscheinlich nützlichste Hinweis ist der User-Agent-String, der bei jeder Anfrage über den User-Agent-Header bereitgestellt wird. Daher funktioniert hier derselbe UA-Sniffing-Ansatz. Tatsächlich tun dies die DeviceAtlas- und WURFL-Projekte bereits (und liefern eine ganze Reihe zusätzlicher Informationen zum Gerät).
Leider stellen diese Optionen jeweils eigene Herausforderungen dar. WURFL ist sehr groß und enthält 20 MB XML, was bei jeder Anfrage zu einem erheblichen serverseitigen Overhead führen kann. Es gibt Projekte, bei denen das XML aus Leistungsgründen aufgeteilt wird. DeviceAtlas ist keine Open-Source-Software und erfordert eine kostenpflichtige Lizenz.
Es gibt auch einfachere, kostenlose Alternativen, z. B. das Projekt Detect Mobile Browsers. Der Nachteil ist natürlich, dass die Geräteerkennung zwangsläufig weniger umfassend ist. Außerdem wird nur zwischen Mobil- und anderen Geräten unterschieden. Tablets werden nur durch ad-hoc-Optimierungen unterstützt.
Ansatz 2: Clientseitige Erkennung
Mithilfe der Funktionserkennung können wir viel über den Browser und das Gerät des Nutzers erfahren. Wir müssen vor allem herausfinden, ob das Gerät Touchbedienung unterstützt und ob es einen großen oder kleinen Bildschirm hat.
Wir müssen irgendwo eine Grenze ziehen, um zwischen kleinen und großen Touchgeräten zu unterscheiden. Wie sieht es mit Grenzfällen wie dem 5" Galaxy Note aus? Die folgende Grafik zeigt eine Reihe beliebter Android- und iOS-Geräte (mit entsprechenden Bildschirmauflösungen). Das Sternchen gibt an, dass das Gerät mit doppelter Dichte geliefert wird oder geliefert werden kann. Auch wenn die Pixeldichte verdoppelt wird, werden in CSS weiterhin dieselben Größen angegeben.
Kurzer Hinweis zu Pixeln in CSS: CSS-Pixel im mobilen Web sind nicht dasselbe wie Bildschirmpixel. Auf iOS-Retina-Geräten wurde die Pixeldichte verdoppelt (z. B. iPhone 3GS im Vergleich zu iPhone 4, iPad 2 im Vergleich zu iPad 3). Die UAs für Retina-Displays in Safari für Mobilgeräte melden weiterhin dieselbe Gerätebreite, um Web-Brüche zu vermeiden. Wie bei anderen Geräten (z. B. Android) Displays mit höherer Auflösung erhalten, wird derselbe Trick mit der Gerätebreite angewendet.
Diese Entscheidung wird jedoch dadurch erschwert, dass sowohl das Hoch- als auch das Querformat berücksichtigt werden müssen. Wir möchten die Seite nicht jedes Mal neu laden oder zusätzliche Scripts laden, wenn wir das Gerät neu ausrichten, möchten die Seite aber möglicherweise anders rendern.
Im folgenden Diagramm stehen die Quadrate für die maximalen Abmessungen der einzelnen Geräte, die durch Überlagern der Umrisse im Hoch- und Querformat entstehen (und das Quadrat vervollständigen):
Wenn wir den Grenzwert auf 650px
festlegen, werden iPhone und Galaxy Nexus als „smalltouch“ und iPad und Galaxy Tab als „Tablet“ klassifiziert. Das androgyne Galaxy Note wird in diesem Fall als „Smartphone“ klassifiziert und erhält das Smartphone-Layout.
Eine angemessene Strategie könnte so aussehen:
if (hasTouch) {
if (isSmall) {
device = PHONE;
} else {
device = TABLET;
}
} else {
device = DESKTOP;
}
Hier sehen Sie ein minimales Beispiel für den Ansatz der Merkmalserkennung in der Praxis.
Alternativ können Sie den Gerätetyp mithilfe von UA-Sniffing ermitteln. Sie erstellen im Grunde eine Reihe von Heuristiken und gleichen sie mit den navigator.userAgent
des Nutzers ab. Pseudocode sieht in etwa so aus:
var ua = navigator.userAgent;
for (var re in RULES) {
if (ua.match(re)) {
device = RULES[re];
return;
}
}
Hier finden Sie ein Beispiel für die UA-Erkennung in Aktion.
Hinweis zum clientseitigen Laden
Wenn Sie die UA-Erkennung auf Ihrem Server ausführen, können Sie festlegen, welches CSS, JavaScript und DOM bei einer neuen Anfrage gesendet werden soll. Bei der clientseitigen Erkennung ist die Situation jedoch komplexer. Sie haben mehrere Möglichkeiten:
- Weiterleitung zu einer gerätetypspezifischen URL, die die Version für diesen Gerätetyp enthält.
- Die gerätespezifischen Assets werden dynamisch geladen.
Der erste Ansatz ist unkompliziert und erfordert eine Weiterleitung wie window.location.href = '/tablet'
. Dem Standort werden jetzt jedoch diese Informationen zum Gerätetyp angehängt. Sie können die URL mit der History API bereinigen. Leider ist bei diesem Ansatz eine Weiterleitung erforderlich, die insbesondere auf Mobilgeräten langsam sein kann.
Der zweite Ansatz ist wesentlich komplexer zu implementieren. Sie benötigen einen Mechanismus zum dynamischen Laden von CSS und JS. Je nach Browser können Sie <meta viewport>
möglicherweise nicht anpassen. Da es keine Weiterleitung gibt, bleibt Ihnen nur die ursprüngliche HTML-Seite, die gesendet wurde. Natürlich können Sie sie auch mit JavaScript bearbeiten, was je nach Anwendung jedoch langsam und/oder unelegant sein kann.
Client oder Server auswählen
Das sind die Vor- und Nachteile der beiden Ansätze:
Pro-Kunde:
- Sie sind zukunftssicherer, da sie nicht auf UA, sondern auf Bildschirmgrößen und -funktionen basieren.
- Die UA-Liste muss nicht ständig aktualisiert werden.
Pro-Server:
- Vollständige Kontrolle darüber, welche Version auf welchen Geräten ausgeliefert werden soll.
- Bessere Leistung: Es sind keine Clientweiterleitungen oder dynamischen Ladevorgänge erforderlich.
Ich persönlich beginne mit device.js und der clientseitigen Erkennung. Wenn sich Ihre Anwendung weiterentwickelt und Sie feststellen, dass das clientseitige Weiterleiten zu einem erheblichen Leistungsnachteil führt, können Sie das device.js-Script ganz einfach entfernen und die UA-Erkennung auf dem Server implementieren.
device.js
Device.js ist ein Ausgangspunkt für die semantische, media query-basierte Geräteerkennung, ohne dass eine spezielle serverseitige Konfiguration erforderlich ist. So sparen Sie Zeit und Aufwand beim Parsen von User-Agent-Strings.
Sie sollten oben in Ihrer <head>
Suchmaschinen-freundliches Markup (link rel=alternate) angeben, das angibt, welche Versionen Ihrer Website Sie bereitstellen möchten.
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
Als Nächstes können Sie entweder die serverseitige UA-Erkennung durchführen und die Versionsweiterleitung selbst verwalten oder das Skript „device.js“ verwenden, um eine funktionsbasierte clientseitige Weiterleitung durchzuführen.
Weitere Informationen finden Sie auf der Projektseite für device.js und in einer gefälschten Anwendung, die device.js für die clientseitige Weiterleitung verwendet.
Empfehlung: MVC mit formfaktorspezifischen Ansichten
Sie denken jetzt wahrscheinlich, dass ich Ihnen rate, drei völlig separate Apps zu entwickeln, eine für jeden Gerätetyp. Nein! Die Codefreigabe ist der Schlüssel.
Hoffentlich haben Sie ein MVC-ähnliches Framework wie Backbone oder Ember verwendet. In diesem Fall sind Sie mit dem Prinzip der Aufgabentrennung vertraut, insbesondere damit, dass Ihre Benutzeroberfläche (Darstellungsschicht) von Ihrer Logik (Modellschicht) getrennt sein sollte. Wenn Sie mit MVC noch nicht vertraut sind, können Sie sich mit diesen Ressourcen zu MVC und MVC in JavaScript vertraut machen.
Die geräteübergreifende Story passt gut in Ihr bestehendes MVC-Framework. Sie können Ihre Datenansichten ganz einfach in separate Dateien verschieben und für jeden Gerätetyp eine benutzerdefinierte Datenansicht erstellen. Dann können Sie allen Geräten (mit Ausnahme der Ansichtsebene) denselben Code bereitstellen.
Ihr Projekt könnte die folgende Struktur haben (natürlich können Sie die Struktur auswählen, die für Ihre Anwendung am sinnvollsten ist):
models/ (gemeinsame Modelle) item.js item-collection.js
controllers/ (gemeinsame Controller) item-controller.js
versions/ (Gerätespezifische Inhalte) tablet/ desktop/ phone/ (telefonspezifischer Code) style.css index.html views/ item.js item-list.js
Mit dieser Art von Struktur können Sie vollständig steuern, welche Assets in jeder Version geladen werden, da Sie für jedes Gerät benutzerdefinierte HTML-, CSS- und JavaScript-Dateien haben. Das ist sehr leistungsstark und kann zu der schlanksten und leistungsstärksten Art der Entwicklung für das geräteübergreifende Web führen, ohne auf Tricks wie adaptive Bilder zurückgreifen zu müssen.
Nachdem Sie Ihr bevorzugtes Build-Tool ausgeführt haben, werden alle JavaScript- und CSS-Dateien zu einer einzigen Datei zusammengeführt und minimiert, um das Laden zu beschleunigen. Die Produktions-HTML-Datei sieht dann in etwa so aus (für Smartphones, mit device.js):
<!doctype html>
<head>
<title>Mobile Web Rocks! (Phone Edition)</title>
<!-- Every version of your webapp should include a list of all
versions. -->
<link rel="alternate" href="http://foo.com" id="desktop"
media="only screen and (touch-enabled: 0)">
<link rel="alternate" href="http://m.foo.com" id="phone"
media="only screen and (max-device-width: 650px)">
<link rel="alternate" href="http://tablet.foo.com" id="tablet"
media="only screen and (min-device-width: 650px)">
<!-- Viewport is very important, since it affects results of media
query matching. -->
<meta name="viewport" content="width=device-width">
<!-- Include device.js in each version for redirection. -->
<script src="device.js"></script>
<link rel="style" href="phone.min.css">
</head>
<body>
<script src="phone.min.js"></script>
</body>
Die (touch-enabled: 0)
-Medienabfrage ist nicht standardmäßig (nur in Firefox hinter einem moz
-Anbieterpräfix implementiert), wird aber von device.js dank Modernizr.touch korrekt verarbeitet.
Versionsüberschreibung
Die Geräteerkennung kann manchmal fehlerhaft sein. In einigen Fällen möchte ein Nutzer möglicherweise das Tablet-Layout auf seinem Smartphone sehen (z. B. wenn er ein Galaxy Note verwendet). Daher ist es wichtig, Nutzern die Möglichkeit zu geben, die Version Ihrer Website manuell zu überschreiben.
Normalerweise wird in der mobilen Version ein Link zur Desktopversion bereitgestellt. Das ist einfach zu implementieren, aber device.js unterstützt diese Funktion mit dem GET-Parameter device
.
Fazit
Zusammenfassend lässt sich sagen, dass Sie bei der Erstellung geräteübergreifender One-Page-UIs, die nicht genau in das Konzept des responsiven Designs passen, Folgendes tun sollten:
- Wählen Sie eine Reihe von zu unterstützenden Geräteklassen und Kriterien aus, anhand derer Geräte in Klassen eingeteilt werden sollen.
- Entwerfen Sie Ihre MVC-App mit einer klaren Trennung der Aufgaben und trennen Sie die Ansichten vom Rest der Codebasis.
- Verwende device.js für die clientseitige Geräteklassenererkennung.
- Wenn Sie fertig sind, verpacken Sie Ihr Script und Ihre Stylesheets in jeweils ein Paket pro Geräteklasse.
- Wenn die Leistung der clientseitigen Weiterleitung ein Problem darstellt, sollten Sie device.js nicht mehr verwenden und stattdessen zur serverseitigen UA-Erkennung wechseln.