Dynamisch Fit (Linux-Magazin, August 2014)

Damit eine Webseite sowohl auf dem Desktop als auch auf modernen Mobiltelefonen mit hochauflösender Grafik gut aussieht, muss sie sich mittels CSS und Media Queries dynamisch an den aktuellen Bildschirm anpassen.

Ein Blick auf mein USA-Blog auf http://usarundbrief.com offenbart, dass das Seitenlayout mehr als zehn Jahre alt ist. In der Welt der Mode sollen Trends ja etwa alle 30 Jahre wiederkehren, allerdings halte ich es für äußerst unwahrscheinlich, dass uns das Webdesign der frühen Nullerjahre in Kürze wieder beehrt. Die Website habe ich damals mit dem Perl-Template-Toolkit aufgezogen, unter strikter Trennung von Inhalt (mittlerweile auf Github [2]) und Layout, und so sollte es nicht schwerfallen, das Nullerdesign einem radikalen Makeover zu unterwerfen.

Wenn man einmal von bunten Kästen mit runden Ecken und anderem Firlefanz absieht, zeichnet sich gutes Webdesign heute vor allem dadurch aus, dass der Inhalt einer Website auf den kleinen Displays von Mobiltelefonen genauso lesbar ist wie auf einem Monstermonitor Modell Donnerschlag (https://www.apple.com/displays). Das lösen manche Seitenanbieter durch spezielle Mobilseiten, zu denen sie den Browser lotsen, sobald sie anhand des Useragent-Headers feststellen, dass der User auf ein klitzekleines Display in seiner Hand starrt und auf einmal kein Verständnis mehr für Navigationselemente aufbringt, die sich zwar mit einem Mauszeiger gut anwählen, aber mit dicken Fingern unmöglich bedienen lassen.

Nach der Lehre des "Responsive Design" stecken Webentwickler aber nicht extra Aufwand in dezidierte Mobilseiten, sondern gehen einen resourcensparenderen Weg. Mittels CSS und sogenannten "Media Queries" antwortet damit ein und dieselbe HTML-Seite unterschiedlich auf Displays mit verschiedenen Leistungsmerkmalen. Der Browser lässt dann auf kleineren Bildschirmen manche Navigationselemente weg, verkleinert die Logos oder zeigt manche Bereiche statt seitlich nebeneinander auf einmal übereinander an.

Mit Zwicker und Leselupe

Vor allem stört auf kleinen Displays aber ein Feature, mit dem die ersten richtigen Smartphones auf einmal das Web auf Mobilgeräten lesbar machten: Trotz Platzmangel auf dem Display schneiden die moderen Mobilbrowser angezeigte Seiten nicht ab, sondern zoomen so weit heraus, dass die gesamte Seitenbreite erscheint. Deren Inhalt kann dann allerdings kein Mensch mehr lesen und User sind erstmal damit beschäftigt, die Darstellung mittels der Zwei-Finger-Geste auf eine lesbare Schriftgröße auszudehnen und dann mittels Panning wie mit einer Lupe im Inhalt herumzufahren (Abbildung 2).

Abbildung 1: Auf einem breiten Desktop stören Navigationselemente neben dem Inhalt nicht.

Abbildung 2: Das iPhone zeigt die Seite auf großer Distanz, sodass sie zwar in voller Breite erscheint, aber ohne ranzoomen nicht mehr lesbar ist.

Eine Seite, die nun alle Displaygrößen gleichermaßen bedient, schaltet zu allererst einmal das Zoom-Feature ab. Mit dem Tag

   <meta name="viewport" content="width=device-width,initial-scale=1.0">

im Header-Teil des HTML-Dokuments bricht allerdings dabei auf kleinen Displays das (gewollte) Chaos herein, denn wie in Abbildung 3 sichtbar, schneidet der Browser nun gnadenlos den rechten Teil der Seite ab, inklusive Teile des Inhalts auf der linken Seite. Statt Textinhalt blickt der User vielmehr auf riesige Logos und Navigationselemente. Der Desktop-User bleibt davon unbeeindruckt, denn er sieht nach wie vor das Original-Layout. Klar ist: Nach diesem ersten Schritt muss die Seite ihren Inhalt dynamisch neu strukturieren, falls sie bemerkt, dass ein Handy-User darin herumstöbert.

Abbildung 3: Die meta-Anweisung an den Viewport im HTML unterdrückt die Zoomfunktion des iPhones.

Handy mit Monstermonitor

Doch die Vielfalt heute genutzter Geräte verkompliziert die Lage: Ein iPad Mini mit Retina-Screen verfügt über eine Auflösung von 2048x1536 Pixeln, mehr als so mancher Desktop-Monitor vor ein paar Jahren, der immer noch klaglos seinen Dienst tut. Selbst Smartphones wie das HTC One bieten auf nur 12cm Diagonale sagenhafte 1080x1920 Pixel Auflösung. Eine Webseite, die für eine breite Palette von Endgeräten die optimale Darstellung wählt, muss also nicht nur die Auflösung des verwendeten Displays berücksichtigen, sondern auch die Pixeldichte, damit sie nicht zuviele Informationen in zuwenig Freiraum zwängt.

Wie zum Beispiel in ([3]) erläutert, schalten moderne Webseiten die Darstellung über sogenannte Media-Queries um. Der CSS-Teil einer Seite fragt ab, wie breit ein "Viewport", also die aktuelle Größe des Browserfensters, ist, und aktiviert, deaktiviert oder verschiebt dann ausgezeichnete <div>-Elemente im HTML-Teil. Dies alles passiert auf ein und derselben Webseite, die der Browser vom Server lädt, der von der dynamisch angepassten Darstellung nichts mitbekommt, da alles Client-seitig im Browser passiert.

Listing 1: test.html.tt

    1 [% INCLUDE 'header.html.tt' %]
    2 <body>
    3     <div id="nav">
    4       Navigation Bar
    5     </div>
    6     <div id="main">
    7       Main Content
    8     </div>
    9 </body>

Listing 1 zeigt als Beispiel den HTML-Teil einer Seite mit einem Navigationselement mit der ID "nav" und einem Textteil namens "main". Der vorstehende Header-Teil der Seite, der mittels der INCLUDE-Anweisung des Perl-Template-Toolkits hereingezogen wird, befindet sich in Listing 2 und birgt neben der eingangs erläuterten Viewport-Anweisung zum Ausschalten der Handy-Zoomfunktion einige statische CSS-Anweisungen, sowie zwei mit dem Schlüssel @media eingeleitete Media-Queries, die die weiter oben stehende statische Anweisungen überschreiben, falls sie feststellen, dass das Endgerät bestimmte Voraussetzungen erfüllt.

Listing 2: header.html.tt

    01 <!DOCTYPE html>
    02 <html>
    03   <head>
    04     <meta name="viewport" 
    05      content="width=device-width,initial-scale=1.0">
    06   <style>
    07 
    08   #nav {
    09     float: top;
    10     display: block;
    11     border: 6px solid green;
    12   }
    13   #main {
    14     float: bottom;
    15     display: block;
    16     border: 6px solid pink;
    17   }
    18 
    19 @media only screen and (max-width: 640px),
    20     only screen and (max-width: 1080px) and
    21       (-webkit-min-device-pixel-ratio: 2.0) {
    22     [% INCLUDE hidenav.css.tt %]
    23 }
    24 
    25 @media only screen and (orientation: landscape) {
    26     [% INCLUDE sidebyside.css.tt %]
    27 }
    28 
    29   </style>
    30 </head>

Nur für neue Browser

So bestimmt der Media-Query in Zeile 19 von Listing 2 mit dem einleitenden Kommando only screen and ..., dass er nur auf Bildschirmdarstellungen agiert (also nicht in der Druckdarstellung) und mit and weitere, nachfolgende Bedingungen knüpft. Das Schlüsselwort only weist ältere Browser ab, die den nachfolgenden Query eh nicht verstünden. Der Query "max-width: 640px" passt auf alle Browser, deren Fenster schmäler als 640 Pixel ist. Durch ein Komma getrennt folgt eine weitere, mit einem logischen Oder verknüpfte Bedingung, die wiederum eine screen voraussetzt, und auf hochauflösenden Retina-Displays mehr Breitenpixel zulässt. Der Wert für -webkit-min-device-pixel-ratio ist für einen altgediegenen Monitor 1.0 und auf einem Retina-Display 2.0, wie sich auf [4] feststellen lässt (Abbildungen 4 und 5).

Abbildung 4: Auf einem Desktop-Monitor ist die Pixeldichte 1.0.

Abbildung 5: Auf einem iPhone ist die Pixeldichte 2.0.

Auf Geräten mit kleinen Bildschirmen, egal ob diese mit Hochauflösung protzen oder nicht, holt der Media-Query aus Zeile 19 also die Datei hidenav.css.tt aus Listing 3. Dieses setzt den Wert für das Attribut display des div-Elements mit der ID nav auf none, unterbindet also die Darstellung des Navigationselements. Weiter setzt es die Variable float für das Inhaltselement main auf top, lässt das div-Element also am oberen Fensterrand schweben.

Listing 3: hidenav.css.tt

    1   #nav {
    2     display: none
    3   }
    4   #main {
    5     float: top
    6   }

Schlanker im Mobilformat

Ein auf die Webseite zeigender Desktop-Browser zeigt wie aus Abbildung 6 ersichtlich sowohl den Navigationsbalken als auch den Block mit dem Text untereinander an. Schiebt der User das Browserfenster jedoch auf unter 640 Pixel Breite zusammen, schaltet der Browser wegen des adaptiven CSS-Layouts in den Mobilmodus um, lässt das Navigationselement sausen und zeigt nur noch den Textblock an (Abbildung 7).

Abbildung 6: Ist das Fenster weiter als auf 640 Pixel aufgezogen, erscheint der Navigationsbalken.

Abbildung 7: Verringert der User die Fensterbreite unter 640 Pixels, erscheint auch auf dem Desktop die Mobilversion der Seite.

Auf einem 640 Pixel breiten Display eines iPhone 5 erscheint wegen des Media-Queries ebenfalls die gewünschte Mobilversion ohne Navigation (Abbildung 8). Der zweite Media-Query in Listing 2 ab Zeile 25 frägt noch ein weiteres Darstellungsmerkmal der Anzeige ab. Mittels (orientation: landscape) prüft er, ob die Anzeige im Querformat arbeitet. Ist das der Fall, kommt der Code in Datei sidebyside.css.tt aus Listing 4 zum Einsatz, der Navigations- und Textelement nebeneinander darstellt, und dem Inhalt 70% einräumt und der Navigation nur 30%. Den Wert für die Variable display des Nav-Elements setzt Listing 5 auf "block", um eine eventuell im vorangegangenen Media-Query erfolgte Zuweisung des Wertes "none" zu überschreiben und den ursprünglich im statischen CSS-Anweisungsblock zugewiesenen Wert "block" wiederherzustellen. Eine Liste von Media-Queries arbeitet der Browser von oben nach unten ab und überschreibt jedes Mal bislang zugewiesene Werte, falls die vorgegebenen Bedingungen zutreffen.

Listing 4: sidebyside.css.tt

    1   #nav {
    2     float: right;
    3     width: 30%;
    4     display: block;
    5   }
    6   #main {
    7     float: left;
    8     width: 60%;
    9   }

Abbildung 8: Auf dem iPhone 5 erscheint wegen der Seitenbreite von 640 Pixeln die Mobilversion.

Als Resultat erscheinen in Abbildung 9 beide Blöcke nebeneinander, denn obwohl der erste Media-Query nur den Textblock ohne den Navigationsblock zulässt, überschreibt der Landscape Query alle vorherigen Einstellungen und setzt beide Blöcke im Verhältnis 70/30 nebeneinander.

Abbildung 9: Im Querformat erscheinen Inhalt und Navigationsleiste nebeneinander.

Baukastensystem

Das CPAN-Modul des Perl-Template-Toolkits baut die komplette Seite aus den Template-Einzelteilen mit dem Kommando

    tpage --include_path templates templates/test.html.tt >test.html

zusammen und verbindet so die entwicklungsfreundliche modulare Aufteilung mit voller Performance auf der Client- und Serverseite. Zwar kann man den Browser anweisen, bestimmte externe CSS-Seiten nur dann zu laden, falls ein angegebener Media-Query einen wahren Wert zurückliefert, doch jeder Ladevorgang kostet wertvolle Zeit.

Wer schnell mit einem lokal laufenden Webserver testen möchte, kann dies mit einem kurzen Skript mit dem CPAN-Modul Mojolicious::Lite tun, wie in Listing 5 gezeigt.

Listing 5: mojo

    01 #!/usr/local/bin/perl -w
    02 use strict;
    03 use Mojolicious::Lite;
    04  
    05 @ARGV = qw( daemon --listen http://*:4080 );
    06 
    07 plugin 'tt_renderer';
    08  
    09 get '/' => sub {
    10   my $self = shift;
    11   $self->render('index');
    12 };
    13  
    14 app->start;
    15  
    16 __DATA__
    17  
    18 @@ index.html.tt
    19 [% INCLUDE 'header.html.tt' %]
    20 [% INCLUDE 'test.html.tt' %]

Es startet einen voll funktionsfähigen Server auf Port 4080 auf localhost und ein dorthin zeigender Browser wird die Seite unterschiedlich anzeigen, je nach dem, ob das Browserfenster weit aufgezogen, schmal zugezogen, oder ins Querformat gestellt ist. Um mit dem Template-Toolkit zu kommunizieren, benötigt das Skript weiter das CPAN-Modul Mojolicious::Plugin::TtRenderer.

Wer tiefer in die Materie eindringen möchte, dem sei das Buch "Responsive Web Design with HTML5 and CSS3" von Ben Frain empfohlen ([2]). Es stellt eine Vielzahl praxisorientierter Anwendungsbeispiele vor und erläutert Techniken zum dynamischen Seitenlayout und dem Anpassen der Bildergrößen für verschiedene Mobil- und Desktopgeräte.

Infos

[1]

Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2014/08/Perl

[2]

Github-Repository mit dem Inhalt von http://usarundbrief.com: https://github.com/mschilli/usarundbrief

[2]

"Responsive Web Design with HTML5 and CSS3", Ben Frain, Packt Publishing, 2012

[3]

"Responsive Web Design", Ethan Marcotte, 2010, http://alistapart.com/article/responsive-web-design/

[4]

Device pixel density tests: http://bjango.com/articles/min-device-pixel-ratio/

Michael Schilli

arbeitet als Software-Engineer bei Yahoo in Sunnyvale, Kalifornien. In seiner seit 1997 laufenden Kolumne forscht er jeden Monat nach praktischen Anwendungen der Skriptsprache Perl. Unter mschilli@perlmeister.com beantwortet er gerne Ihre Fragen.