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.
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. |
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.
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.
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>
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.
1 #nav { 2 display: none 3 } 4 #main { 5 float: top 6 }
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.
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. |
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.
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.
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2014/08/Perl
Github-Repository mit dem Inhalt von http://usarundbrief.com: https://github.com/mschilli/usarundbrief
"Responsive Web Design with HTML5 and CSS3", Ben Frain, Packt Publishing, 2012
"Responsive Web Design", Ethan Marcotte, 2010, http://alistapart.com/article/responsive-web-design/
Device pixel density tests: http://bjango.com/articles/min-device-pixel-ratio/