Ein nicht responsiver Ansatz zum Erstellen geräteübergreifender Web-Apps

Smus
Boris Smus

Medienabfragen sind toll, aber...

Medienabfragen sind großartig. Für Website-Entwickler, die kleine Änderungen an ihren Stylesheets vornehmen möchten, um die Nutzerfreundlichkeit auf Geräten unterschiedlicher Größe zu verbessern, sind Medienabfragen genial. Mit Medienabfragen können Sie im Wesentlichen das CSS Ihrer Website je nach Bildschirmgröße anpassen. Bevor Sie mit diesem Artikel beginnen, 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 erwähnt hat, ist das Ändern des Designs nur einer von vielen Dingen, die bei der Entwicklung für das mobile Web zu berücksichtigen sind. Wenn Sie beim Erstellen Ihrer mobilen Website nur das Layout mit Medienabfragen anpassen, liegt die folgende Situation vor:

  • Alle Geräte erhalten denselben JavaScript- und CSS-Code und dieselben Assets (Bilder und Videos), was zu längeren Ladezeiten führt.
  • Alle Geräte erhalten dasselbe anfängliche DOM, wodurch Entwickler möglicherweise übermäßig komplizierten CSS-Code schreiben müssen.
  • Geringe Flexibilität, um benutzerdefinierte Interaktionen für jedes Gerät festzulegen

Web-Apps benötigen mehr als Medienabfragen

Verstehen Sie mich nicht falsch. Ich hasse responsives Design über Medienabfragen nicht und denke definitiv, dass es auf der Welt einen Platz hat. Darüber hinaus können einige der oben genannten Probleme mit Ansätzen wie responsiven Bildern, dem dynamischen Laden von Skripts usw. gelöst werden. Ab einer bestimmten Zeit kann es jedoch vorkommen, dass Sie zu viele inkrementelle Optimierungen vornehmen, sodass die Bereitstellung unterschiedlicher Versionen möglicherweise besser ist.

Da die erstellten UIs immer komplexer werden und Sie immer mehr Webanwendungen mit nur einer Seite verwenden, sollten Sie mehr tun, um die Benutzeroberflächen für jeden Gerätetyp anzupassen. In diesem Artikel erfahren Sie, wie Sie diese Anpassungen mit minimalem Aufwand vornehmen können. Im Allgemeinen wird das Gerät des Besuchers der richtigen Geräteklasse zugeordnet, die entsprechende Version für das Gerät bereitgestellt und die Wiederverwendung des Codes zwischen den Versionen maximiert.

Auf welche Geräteklassen zielen Sie ab?

Es gibt unzählige mit dem Internet verbundene Geräte, die fast alle mit einem Browser ausgestattet sind. Die Komplikation liegt in ihrer Vielfalt: Mac-Laptops, Windows-Workstations, iPhones, iPads, Android-Telefone mit Touch-Eingabe, Scrollräder, Tastaturen, Spracheingabe, druckempfindliche Geräte, Smartwatches, Toaster, Kühlschränke und vieles mehr. Einige dieser Geräte sind allgegenwärtig, während andere sehr selten sind.

Eine Vielzahl von Geräten.
Eine Vielzahl von Geräten (Quelle).

Für eine gute Nutzererfahrung 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, wird Ihre Oberfläche frustrierend sein, da sie für andere Bildschirmgrößen und andere Eingabemodalitäten konzipiert ist.

Bei den Ansätzen gibt es zwei extreme Bereiche:

  1. Eine Version erstellen, die auf allen Geräten funktioniert Darunter leidet dann die UX, da für verschiedene Geräte unterschiedliche Designüberlegungen gelten.

  2. Erstellen Sie eine Version für jedes Gerät, das Sie unterstützen möchten. Dieser Vorgang dauert eine Weile, da Sie zu viele Versionen Ihrer Anwendung erstellen werden. Wenn das nächste neue Smartphone eintrifft (was ungefähr wöchentlich stattfindet), müssen Sie eine weitere Version erstellen.

Dabei gibt es einen grundlegenden Vor- und Nachteil: Je mehr Gerätekategorien Sie haben, desto besser können Sie die Nutzererfahrung bieten, aber desto mehr Arbeit ist für Design, Implementierung und Wartung erforderlich.

Das Erstellen einer separaten Version für jede Geräteklasse, für die Sie sich entscheiden, kann aus Leistungsgründen eine gute Idee sein oder wenn die Versionen, die Sie für verschiedene Geräteklassen bereitstellen möchten, stark variieren. Andernfalls ist responsives Webdesign ein durchaus vernünftiger Ansatz.

Eine mögliche Lösung

Hier ein Kompromiss: Klassifizieren Sie die Geräte in Kategorien und entwerfen Sie die bestmögliche User Experience für jede Kategorie. Welche Kategorien Sie wählen, hängt von Ihrem Produkt und Ihrer Zielgruppe ab. Hier ist eine Beispielklassifizierung, die beliebte webfähige Geräte abdeckt, die es heute gibt.

  1. kleine Bildschirme + Touchbedienung (hauptsächlich Smartphones)
  2. große Bildschirme + Touchbedienung (hauptsächlich Tablets)
  3. große Bildschirme + Tastatur/Maus (hauptsächlich Desktop-Computer/Laptops)

Dies ist nur eine von vielen möglichen Aufschlüsselungen, aber zum Zeitpunkt der Erstellung dieses Dokuments sehr sinnvoll. In der obigen Liste fehlen Mobilgeräte, die keinen Touchscreen haben (z. B. Feature-Phones, einige spezielle E-Book-Reader). Auf den meisten dieser Plattformen ist jedoch eine Tastaturnavigation oder eine Screenreader-Software installiert, was gut funktioniert, wenn Sie Ihre Website unter Berücksichtigung der Barrierefreiheit erstellen.

Beispiele für formfaktorspezifische Web-Apps

Es gibt viele Beispiele für Web-Properties, die völlig unterschiedliche Versionen für unterschiedliche Formfaktoren bereitstellen. Die Google-Suche und Facebook. Dabei spielt sowohl die Leistung (Abrufen von Assets, Rendern von Seiten) als auch eine allgemeinere Nutzererfahrung eine Rolle.

In der Welt der systemeigenen Apps entscheiden sich viele Entwickler dafür, die Nutzererfahrung an eine Geräteklasse anzupassen. Flipboard für iPad hat beispielsweise eine ganz andere Benutzeroberfläche als Flipboard auf dem iPhone. Die Tablet-Version ist für die zweihändige Nutzung und horizontales Blättern optimiert, während die Telefonversion für die Einhand-Interaktion und das vertikale Spiegeln vorgesehen ist. Viele andere iOS-Apps bieten ebenfalls deutlich unterschiedliche Smartphone- und Tablet-Versionen, z. B. Things (To-do-Liste) und Showyou (Videos für soziale Medien), die unten zu sehen sind:

Erhebliche Anpassung der Benutzeroberfläche für Smartphone und Tablet
Benutzeroberfläche, die für Smartphones und Tablets umfassend angepasst werden kann.

1. Ansatz: Serverseitige Erkennung

Auf dem Server haben wir ein viel begrenzteres Verständnis für das Gerät, mit dem wir es zu tun haben. Der wahrscheinlich nützlichste Anhaltspunkt ist der User-Agent-String, der bei jeder Anfrage über den User-Agent-Header bereitgestellt wird. Aus diesem Grund funktioniert hier derselbe UA-Sniffing-Ansatz. Bei den Projekten DeviceAtlas und WURFL ist dies sogar bereits der Fall (und liefern viele zusätzliche Informationen über das Gerät).

Leider stellt jede dieser Strategien eigene Herausforderungen dar. WURFL ist mit 20 MB XML sehr groß und kann bei jeder Anfrage erheblichen serverseitigen Aufwand verursachen. Bei einigen Projekten wird der XML-Code aus Leistungsgründen aufgeteilt. DeviceAtlas ist keine Open Source und erfordert eine kostenpflichtige Lizenz.

Es gibt auch einfachere, kostenlose Alternativen, wie das Projekt Detect Mobile Browsers. Der Nachteil ist natürlich, dass die Geräteerkennung zwangsläufig weniger umfassend ist. Außerdem wird nur zwischen mobilen und Nicht-Mobilgeräten unterschieden, sodass Tablets nur durch eine Ad-hoc-Reihe von Änderungen eingeschränkt werden können.

2. Ansatz: Clientseitige Erkennung

Durch die Funktionserkennung können wir viel über den Browser und das Gerät des Nutzers lernen. Zuerst müssen wir feststellen, ob das Gerät Touchfunktionen hat und ob es sich um einen großen oder einen kleinen Bildschirm handelt.

Wir müssen irgendwo eine Grenze ziehen, um kleine von großen Touch-Gerä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 übereinander (mit entsprechenden Bildschirmauflösungen). Das Sternchen gibt an, dass das Gerät eine doppelte Pixeldichte hat oder haben kann. Obwohl die Pixeldichte möglicherweise verdoppelt wird, meldet CSS dennoch dieselben Größen.

Ein kleiner Hinweis zu Pixeln in CSS: CSS-Pixel im mobilen Web sind nicht dasselbe wie Bildschirmpixel. Auf iOS-Retina-Geräten wurde die Verdopplung der Pixeldichte eingeführt (z. B. iPhone 3GS vs. 4, iPad 2 vs. 3). Die Retina Mobile Safari-UAs melden weiterhin dieselbe Gerätebreite, um das Web nicht zu unterbrechen. Wie bei anderen Geräten (z. B. Android) höhere Auflösungen erhalten, verwenden sie den gleichen Trick in Bezug auf die Gerätebreite.

Geräteauflösung (in Pixeln)
Geräteauflösung (in Pixeln).

Erschwert wird diese Entscheidung jedoch, wenn sowohl das Hoch- als auch das Querformat berücksichtigt werden. Wir möchten nicht bei jeder Neuausrichtung des Geräts die Seite neu laden oder zusätzliche Skripts laden, auch wenn wir die Seite anders rendern möchten.

Im folgenden Diagramm stellen Quadrate die maximalen Abmessungen der einzelnen Geräte dar, die sich aus der Überlagerung der Hoch- und Querformate sowie der Vervollständigung des Quadrats ergeben:

Hochformat- und Querformatauflösung (in Pixel)
Hoch- und Querformatauflösung (in Pixeln)

Wenn Sie den Schwellenwert auf 650px setzen, werden iPhone, Galaxy Nexus und iPad als „Tablet“ klassifiziert. Die androgyne Galaxy Note wird in diesem Fall als „Telefon“ klassifiziert und erhält das Telefonlayout.

Eine sinnvolle Strategie könnte also so aussehen:

if (hasTouch) {
  if (isSmall) {
    device = PHONE;
  } else {
    device = TABLET;
  }
} else {
  device = DESKTOP;
}

Sehen Sie sich ein kleines Beispiel für den Ansatz zur Featureerkennung in Aktion an.

Ein alternativer Ansatz ist hier das UA-Sniffing, um den Gerätetyp zu erkennen. Grundsätzlich erstellen Sie eine Reihe von Heuristiken und gleichen sie mit der navigator.userAgent des Nutzers ab. Ein Pseudocode sieht in etwa so aus:

var ua = navigator.userAgent;
for (var re in RULES) {
  if (ua.match(re)) {
    device = RULES[re];
    return;
  }
}

Beispiel für den Ansatz zur UA-Erkennung

Hinweis zum clientseitigen Laden

Wenn Sie die UA-Erkennung auf Ihrem Server durchführen, können Sie entscheiden, welches CSS, JavaScript und DOM bei einer neuen Anfrage bereitgestellt werden. Bei einer clientseitigen Erkennung ist die Situation jedoch komplexer. Sie haben mehrere Möglichkeiten:

  1. Leitet zu einer gerätespezifischen URL weiter, die die Version für diesen Gerätetyp enthält.
  2. Dynamisches Laden der gerätetypspezifischen Assets

Der erste Ansatz ist einfach und erfordert eine Weiterleitung wie window.location.href = '/tablet'. An den Standort werden jetzt jedoch diese Gerätetypinformationen angehängt, sodass Sie Ihre URL mit der History API bereinigen können. Leider umfasst diese Methode eine Weiterleitung, die insbesondere auf Mobilgeräten langsam sein kann.

Die Implementierung des zweiten Ansatzes ist etwas komplizierter. Sie benötigen einen Mechanismus, um CSS und JS dynamisch zu laden. Je nach Browser ist es eventuell nicht möglich, <meta viewport> anzupassen. Da es keine Weiterleitung gibt, bleiben Sie außerdem bei dem ursprünglich bereitgestellten HTML-Code. Natürlich können Sie ihn mit JavaScript manipulieren, aber dies kann je nach Anwendung langsam und/oder nicht praktikabel sein.

Client oder Server entscheiden

Im Folgenden sind die Vor- und Nachteile der Ansätze aufgeführt:

Pro-Client:

  • Zukunftssicherer, da auf Grundlage von Bildschirmgrößen/-fähigkeiten statt UA.
  • Die UA-Liste muss nicht ständig aktualisiert werden.

Pro-Server:

  • Vollständige Kontrolle darüber, welche Version auf welchen Geräten bereitgestellt wird.
  • Bessere Leistung: Clientweiterleitungen und dynamisches Laden sind nicht erforderlich.

Ich bevorzuge es, mit device.js und clientseitiger Erkennung zu beginnen. Wenn Sie im Zuge der Weiterentwicklung Ihrer Anwendung feststellen, dass die clientseitige Weiterleitung erhebliche Leistungseinbußen mit sich bringt, können Sie das Skript device.js einfach entfernen und die UA-Erkennung auf dem Server implementieren.

Jetzt neu: device.js

Device.js ist ein Ausgangspunkt für eine semantische, auf Medienabfragen basierende Geräteerkennung, ohne dass eine spezielle serverseitige Konfiguration erforderlich ist. Dies spart Zeit und Aufwand beim Parsen von User-Agent-Strings.

Der Grundgedanke ist, dass Sie oben in <head> ein suchmaschinenfreundliches Markup (link rel=alternate) einfügen, um anzugeben, 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 eine serverseitige UA-Erkennung vornehmen und die Versionsweiterleitung selbst durchführen oder das Script device.js für eine funktionsbasierte clientseitige Weiterleitung verwenden.

Weitere Informationen finden Sie auf der Projektseite „device.js“ und auf einer fiktiven Anwendung, die „device.js“ für die clientseitige Weiterleitung verwendet.

Empfehlung: MVC mit formfaktorspezifischen Ansichten

Inzwischen denken Sie wahrscheinlich, dass ich Sie ermutige, drei vollständig separate Anwendungen zu erstellen, eine für jeden Gerätetyp. Nein! Code-Sharing ist der Schlüssel.

Hoffentlich haben Sie ein MVC-ähnliches Framework wie Backbone, Ember usw. verwendet. Wenn ja, sind Sie mit dem Prinzip der Trennung von Belangen vertraut, insbesondere mit dem Prinzip, dass Ihre UI (Ansichtsebene) von Ihrer Logik (Modellebene) entkoppelt werden sollte. Wenn Sie damit noch nicht vertraut sind, beginnen Sie mit einigen dieser Ressourcen auf MVC und MVC in JavaScript.

Die geräteübergreifende Story fügt sich nahtlos in Ihr vorhandenes MVC-Framework ein. Sie können Ihre Ansichten ganz einfach in separate Dateien verschieben und für jeden Gerätetyp eine benutzerdefinierte Ansicht erstellen. Dann können Sie denselben Code für alle Geräte außer der Ansichtsebene bereitstellen.

Geräteübergreifender MVC
Geräteübergreifendes MVC

Ihr Projekt kann die folgende Struktur haben (selbstverständlich können Sie die Struktur wählen, die für Ihre Anwendung am sinnvollsten ist):

Modelle/ (gemeinsam genutzte Modelle) item.js item-collection.js

Controller/ (gemeinsam genutzte Controller) item-controller.js

versions/ (gerätespezifisch) tablet/ desktop/ phone/ (telefonspezifischer Code) style.css index.html view/ item.js item-list.js

Mit dieser Art von Struktur können Sie vollständig steuern, welche Assets die einzelnen Versionen laden, da Sie benutzerdefinierten HTML-, CSS- und JavaScript-Code für jedes Gerät haben. Dies ist sehr leistungsstark und kann die schlankeste und leistungsfähigste Methode zur Entwicklung für das geräteübergreifende Web sein, ohne auf Tricks wie adaptive Bilder zurückgreifen zu müssen.

Sobald Sie Ihr bevorzugtes Build-Tool ausgeführt haben, verketten und komprimieren Sie Ihren gesamten JavaScript- und CSS-Code zu einzelnen Dateien, um sie schneller laden zu können. Ihr HTML-Code für die Produktion sieht in etwa so aus (für Telefon, unter Verwendung von 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 standardgemäß (sie wird nur in Firefox hinter einem moz-Anbieterpräfix implementiert), von device.js aber korrekt verarbeitet (dank Modernizr.touch).

Versionsüberschreibung

Die Geräteerkennung kann manchmal schiefgehen. Manchmal ziehen Nutzer es vor, sich das Tablet-Layout auf ihrem Smartphone anzusehen (möglicherweise verwenden sie ein Galaxy Note). Daher ist es wichtig, den Nutzern die Wahl zu lassen, welche Version Ihrer Website sie verwenden möchten, wenn sie sie manuell überschreiben möchten.

Üblicherweise stellen Sie hier einen Link zur Desktopversion von Ihrer mobilen Version bereit. Die Implementierung ist einfach, device.js unterstützt diese Funktion jedoch mit dem GET-Parameter device.

Abschluss

Das bedeutet:

  1. Wählen Sie eine Reihe von zu unterstützenden Geräteklassen und Kriterien aus, nach denen Geräte in Klassen klassifiziert werden sollen.
  2. Erstellen Sie Ihre MVC-Anwendung mit strikter Trennung von Problemen, indem Sie Ansichten vom Rest der Codebasis trennen.
  3. Verwenden Sie device.js, um eine clientseitige Geräteklassenerkennung durchzuführen.
  4. Wenn Sie bereit sind, verpacken Sie Ihr Skript und Ihre Stylesheets in jeweils eins pro Geräteklasse.
  5. Wenn die clientseitige Weiterleitungsleistung ein Problem ist, verwerfen Sie device.js und wechseln Sie zur serverseitigen UA-Erkennung.