Responsive-Webdesign-Tutorial (Vorwort, Einleitung, Kapitel 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Prototyp C – Responsive Layout mit HTML5 und CSS3 (flexibles Layout, flexible Bilder, Media Queries)

Letzte Aktualisierung: 29. Dezember 2013

Nachdem in Kapitel 6 bis 7 die erste Lösungsmöglichkeit beschrieben wurde, folgt hier nun der „Kern“ der Arbeit, die alternative Lösung mit einem reaktionsfähigen Layout. Dieses funktioniert gleichermaßen auf Desktop-PCs und mobilen Geräten.

Die Umstellung erfordert mehrere Maßnahmen:

  • Änderungen wegen HTML5 bzw. Ergänzen von semantischen Auszeichnungen (nicht Pflicht, aber sinnvoll).
  • Umrechnen bzw. Anpassen der Breiten- und Höhenangaben, Schriftgrößen sowie der Innen- und Außenabstände. Alle Angaben werden in relativen Einheiten vorgenommen (%, em, rem).
  • Testen der Website und CSS-Anpassungen in Grenzbereichen. Für manches (z.B. Maximalbreite) reichen Mittel von CSS 2 (max-width). Soll ein spezieller Größenbereich (kleiner oder größer als n Pixel) angesprochen werden, werden Media Queries geschrieben. Dies ist auch der einzige Fall, wo noch Pixel-Angaben im Stylesheet vorkommen.

8.1. HTML-Code (galerie.html)

Nachfolgend wird der vollständige HTML-Code der Seite „Galerie“ (galerie.html). vorgestellt. Diese vereint alle Neuerungen. Wichtiges ist wieder hervorgehoben, die weiteren Quellcodes entnehmen Sie bitte dem Online-Beispiel.

<!DOCTYPE html> <!-- HTML5-Doctype! --> 
<html> 
<head> 
	<meta charset="utf-8"> <!-- Kurzform in HTML5 üblich --> 
	<title>Unternehmenswebsite, Variante C / Galerie</title> 
 
	<link rel="stylesheet" href="style.css"> <!-- type="text/css" nicht notwendig --> 
	<link rel="stylesheet" href="responsive.css"> <!-- enthält nur die Media Queries --> 
 
	<script src="jquery-1.10.1.min.js"></script> <!-- jQuery als Basis (vereinfacht das JavaScript) --> 
	<script src="image-resize.js"></script> <!-- simple Funktion für das Vergrößern/Verkleinern von Bildern (2 Versionen) --> 
 
	<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
</head> 
<body> 
 
<!-- Umschliessendes DIV aus Design-Gründen --> 
<div id="CONTAINER"> 
	<header> <!-- beinhaltet Logo und Hauptnavigation --> 
 
		<div id="left"> 
 
			<div id="logo"> 
				<a href="index.html" style="display:block;"> 
				    <img border="0" src="logo.png" alt="Logo der Unternehmenswebsite" /> 
				</a> 
			</div> 
 
			<nav> <!-- nav fuer die Hauptnavigation --> 
 
				<!-- Navigationsmenue --> 
				<div id="leftmenu"> 
 
					<ul> 
					    <li><a href="index.html">Home</a></li> 
					    <li><a href="leistungen.html">Dienstleistungen</a></li> 
					    <li class="active"><a href="galerie.html">Galerie</a></li> 
					</ul> 
				</div> 
 
			</nav>	 
 
		</div> <!-- Ende left --> 
 
	</header> 
 
	<article> <!-- könnte ein in sich selbstständiger Artikel sein --> 
 
		<div id="content" role="main"> <!-- WAI-ARIA role "main" für den main content der Webseite --> 
 
			<h1>Beispielhafte Unternehmens-website</h1> 
 
			<h2>Prototyp C - Reaktionsfähiges Layout (Responsive)</h2> 
 
			<p> 
			    Die nachfolgende - fiktive - Bildergalerie zeigt Beispiele aus dem Portfolio des Unternehmens: 
			</p> 
 
			<div id="galerie"> 
 
				<!-- geladen wird immer zuerst das kleine Bild (Progressive Enhancement) --> 
				<div class="bild"><img src="person_sehr_klein.png" alt="Beispielbild, Person"></div> 
				<div class="bild"><img src="person_sehr_klein.png" alt="Beispielbild, Person"></div> 
				<div class="bild"><img src="person_sehr_klein.png" alt="Beispielbild, Person"></div> 
				<div class="bild"><img src="person_sehr_klein.png" alt="Beispielbild, Person"></div> 
				<div class="bild"><img src="person_sehr_klein.png" alt="Beispielbild, Person"></div> 
				<div class="bild"><img src="person_sehr_klein.png" alt="Beispielbild, Person"></div> 
 
			</div> 
 
		</div> <!-- Ende content --> 
 
	</article> 
 
		<div style="clear:both;"></div> 
 
	<footer> <!-- Fußbereich --> 
 
		<div id="footer"> 
 
			<!-- Fusszeile mit Impressum etc. --> 
			<div id="footermenu"> 
				<ul> <!-- nicht die Hauptnavigation, deshalb nicht in <nav>...</nav> --> 
				    <li><a href="../browserweiche/">Browserweiche</a></li> 
				    <li><a href="../variante-a/">Variante A</a></li> 
				    <li><a href="../variante-b/">Variante B</a></li> 
				</ul> 
			</div> 
 
			<div id="footerinfo"> 
				&copy; 2013 <a href="http://www.webanwendungen.at/" target="_blank">Ing. Andreas Hammer</a> 
			</div> 
 
		</div> <!-- Ende Footer --> 
 
	</footer> 
 
</div> <!-- Ende CONTAINER --> 
 
 
	<!-- Bilder anpassen in der Galerie --> 
<script> 
		resizeWidth = 820; // entspricht dem Umbruchpunkt der Media Query 
 
	// nach dem Laden der Seite: Bilder skalieren, d.h. größere Bilder laden in der Desktop-Version 
	$(document).ready(function() { 
		resizeImages('galerie', 'person_sehr_klein', 'person_klein', resizeWidth); 
	}); 
 
	// bei Änderung der Fenstergröße ggf. Bilderwechsel 
	$(window).resize(function() { 
		resizeImages('galerie', 'person_sehr_klein', 'person_klein', resizeWidth); 
	}); 
 
</script>
 
</body> 
</html>

Der Quellcode beginnt mit dem sehr kurzen HTML5-Doctype (siehe Abschnitt 2.2). Media Queries wurden der Übersicht halber in ein eigenes Stylesheet (responsive.css) ausgelagert, alle weiteren CSS-Formatierungen (Layout, Inhalt) sind weiterhin in style.css enthalten.

Die Anpassungen der Bilder werden mit JavaScript vorgenommen (siehe unten). Das meta-Tag zum Viewport entspricht dem von Prototyp B und konnte unverändert übernommen werden.

Der <body> enthält nach wie vor DIVs, die semantischen Elemente umschließen diese. Die linke Spalte inkl. Logo und die Hauptnavigation gehören zu <header>, der Hauptinhalt könnte ein eigenständiger Artikel (<article>) sein. Die gesamte Fußzeile wurde als <footer> definiert.

Eine Besonderheit findet sich im DIV des Inhaltsbereichs:

<div id="content" role="main">

Bei role="main" handelt es sich um eine semantische Auszeichnung der WAI-ARIA (= Web Accessibility Initiative / Accessible Rich Internet Applications). Diese sog. „Landmark Roles“ helfen insb. Screenreadern dabei, sich im Quelltext zurecht zu finden. So erfährt ein Screenreader von einem „nichtssagenden“ DIV durch die Rolle main, dass es sich um den Hauptinhaltsbereich handelt. (Anm.: Es wäre technisch auch denkbar, das id-Attribut auf gängige Begriffe (wie hier „content“) zu untersuchen.)

(vgl. Müller, 2011, S. 425ff)
Müller, P. 2011, Das große Little Boxes-Buch - Webseiten gestalten mit HTML & CSS. Grundlagen, Navigation, Inhalte, YAML und mehr, 1. Auflage, Markt+Technik Verlag, München.

8.2. Stylesheet für Layout und Inhalt (style.css)

Bevor auf die JavaScripts eingangen wird, soll noch das – weit wichtigere – Stylesheet style.css erläutert werden. Nachfolgend sind die wichtigsten Passagen abgedruckt:

/* root-Element */ 
html { 
        font-size: 62.5%; /* entspricht meist 10px (wobei 16px oft Browservorgabe ist; 10/16 = 0,625) */ 
                /* ==> 1 rem daher 10px !! */ 
} 
 
/* Umschliessendes DIV, Seitenbreite */ 
div#CONTAINER { 
        width: 90%; /* statt 960px, damit flexibel machen */ 
 
        max-width: 160rem; /* max. Breite (dafür braucht es keine Media Query) */ 
 
        /* Zentrieren der Seite und Abstaende */ 
        margin: 2rem auto 1rem auto; 
} 
 
div#logo img { 
        max-width: 100%; /* Bild skalierbar machen! */ 
} 
 
div#left { 
        padding: 0.1rem; 
 
        min-width: 17rem; /* Mindestbreite, hierfür keine Media Query notwendig; Logo darf geringfügig verkleinert werden */ 
        width: 22.9166666667%; /* = 220/960 */ 
 
        float: left; 
 
        text-align: center; /* Logo und Menue zentrieren */ 
        background-color: white; 
        border: 0.1rem solid black; 
        border-radius: 1.5rem 1.5rem 0 0; /* runde Ecken, nur Optik */ 
 
        margin-right: 2rem; 
} 
 
/* Inhaltsbereich */ 
div#content { 
        overflow: hidden; 
 
        min-width: 11rem; /* Mindestbreite, hierfür keine Media Query notwendig */ 
 
        min-height: 46.875%; /* 450/960 */ 
        padding: 3rem; 
 
        background-color: white; 
        border: 0.1rem solid black; 
        border-radius: 1.5rem 1.5rem 0 0; /* runde Ecken, nur Optik */ 
}

Grundprinzip bei der Umstellung auf ein reaktionsfähiges Layout ist, dass fixe Größen (Pixel-Angaben) anhand eines Bezugspunkts (= „Kontext“) in relative Werte umgerechnet werden. In Variante A (fixes Layout) hat #CONTAINER eine Breite von 960px, das ist der Bezugspunkt bzw. Kontext. #left hat eine fixe Breite von 220px, das ist die Zielgröße. Im reaktionsfähigen Layout hat #left folglich eine Breite von 220 / 960 = 22,9166666667%. Da Rundungsfehler das Layout negativ beeinflussen können, sollten möglichst viele Nachkommastellen angegeben werden.

(vgl. Zillgens, 2013, S. 16ff)
Zillgens, Ch. 2013, Responsive Webdesign: Reaktionsfähige Websites gestalten und umsetzen, 1. Auflage, Carl Hanser Verlag, München.

Nach diesem Prinzip werden weitere Breitenangaben umgerechnet. Am Ende entfernt man den Bezugspunkt (960px) und ersetzt auch diesen durch einen relativen Wert, im Beispiel 90%, wobei dieser willkürlich gewählt wurde (= 90% des Parent-Elements, hier <body>). Ohne diese Maßnahme würde ein Vergrößern oder Verkleinern des Fensters keine Änderung bewirken – erst damit wird das Layout flexibel. Über max-width: 100% wird auch das Logo skalierbar gemacht (siehe Abschnitt 3.2).

Neben Breiten und Höhen müssen auch alle weiteren Pixel-Angaben umgerechnet werden (Schriftgröße, Innen- und Außenabstände, Rahmen). Im Beispiel wird eine sehr einfache Lösung angewandt: alle Pixel-Angaben werden in die Einheit „rem“ umgerechnet. Diese bezieht sich immer auf die Schriftgröße des root-Elements der Webseite (das ist <html>, nicht <body>!). Achtung: In den Kapiteln 1 bis 4 (Theorie) wurde mit der – älteren – Einheit em gerechnet, die sich auf das Parent-Element bezieht.

(vgl. Dr. Web Magazin, 2013)
Dr. Web Magazin 2013, „'CSS gerootet': Flexible Schriftgrößen mit REM“, Abruf am 23.06.2013, http://www.drweb.de/magazin/css-gerootet-flexible-schriftgroessen-mit-rem-38784/

Dabei kann rem nicht nur für Schriftgrößen, sondern auch alle anderen Größenangaben verwendet werden. In Prototyp C wird sogar noch eine weitere Vereinfachung getroffen. 16px ist der gängige Browserstandard in der Schriftgröße. Über

html { font-size: 62.5%; }

wird der Umrechnungsfaktor auf 10 festgesetzt (10 / 16 = 62,5%). Aus 1px im CSS-Code wird 0,1rem (1 / 10 = 0,1), aus 10px wird 1rem usw.

Achtung: Verwendet man diese Methode bei padding und margin (wie im Beispiel), hat das den Nachteil, dass Abstände nicht flexibel skaliert werden. Stattdessen werden sie über rem an die Schriftgröße in <html> gekoppelt. Ändert man diese, vergrößern sich auch alle Abstände mit. Nach Meinung des Autors dieser Arbeit sind Innen- und Außenabstände im Beispiel (Prototyp C) von untergeordneter Bedeutung. Setzt man auch diese Größenangaben in %, ändert sich das Layout beim Skalieren nur geringfügig.

8.3. Behandlung der Grenzfälle – Stylesheet responsive.css

Mit der Umrechnung allein ist es noch nicht getan. Bei sehr kleiner Bildschirmgröße (unter 500px) kommt es sonst zu Problemen:

Prototyp C / Startseite bei geringer Bildschirmbreite (unter 500px)

Wie in Abb. 6 zu sehen ist, hat der Inhaltsbereich eine unansehnliche Breite erreicht (schlechte Lesefreundlichkeit) und zu lange Worte werden abgeschnitten (wegen overflow: hidden für das Einschließen der DIVs in #content). Um es nicht so weit kommen zu lassen, werden mit einer Media Query abweichende CSS-Anweisungen definiert (Auszug aus der responsive.css):

@media only screen and (max-width: 820px) { 
/* Anweisungen für Fenster/Bildschirme bis 820px */ 
 
    div#left { 
            width: 100%;
 
            /* sonst ist #left um den Rahmen zu groß bei 100% width */ 
            -webkit-box-sizing: border-box; 
               -moz-box-sizing: border-box; 
                    box-sizing: border-box; 
    } 
 
    div#content { 
            margin-top: 0; 
            margin-left: auto; 
            margin-bottom: 0; 
            clear: both;
 
            border-radius: 0; 
            border-top: 0; 
    } 
 
 
/* [...] */ 
}

Die Media Query wurde für Auflösungen bis 820px definiert (siehe Abschnitt 3.3). Liegt der Viewport also bei 820px oder darunter (0-820px), wird der mit der Media Query definierte CSS-Code ausgeführt (sonst nicht). Die wichtigste Maßnahme ist das Clearen in #content, wodurch der Inhaltsbereich unterhalb des Menüs erscheint. Über width: 100% wird das Menü auf die volle Größe gebracht. Daneben gibt es einige andere – optische – Änderungen, insb. bei Rahmen, Abständen und den Navigationsmenüs.

Für den oberen Screenshot wurde das Stylesheet responsive.css deaktiviert. Die nächste Abbildung zeigt die (verbesserte) Website bei 400px Breite (bei geladener responsive.css):

Prototyp C / Startseite bei 400px Breite (mit Media Query)

8.4. Skalieren der Bildergalerie (JavaScript)

Abschließend folgt die Erklärung des verwendeten JavaScript-Codes.
Zu Beginn wird jQuery eingebunden:

<script src="jquery-1.10.1.min.js"></script>

Das bringt eine Vereinfachung beim Event-Handling1Über $(window).resize() wird die Größenänderung des Fensters (bzw. Viewports) überwacht (und die definierte Funktion ausgeführt). $(document).ready() setzt das onload-Ereignis (im Beispiel ist das das erstmalige Skalieren der Bilder) (siehe jQuery API Documentation). und Ansprechen der DIVs (Funktion $() statt document.getElementById()) bringt. jQuery könnte also auch weggelassen werden, das hätte aber einen längeren und komplizierteren JavaScript-Code zur Folge. Die Anpassung der Bilder erledigt die Funktion resizeImages():2Ursprünglich wurde ein anderer Ansatz mit der Library Responsive Enhance verfolgt, vom Autor nach einigen wenig zufriedenstellenden Versuchen zugunsten dieses einfacheren Ansatzes allerdings verworfen. Nach Meinung des Autors löst „Responsive Enhance“ die Aufgabe nur dann, wenn ein umgebendes DIV bereits automatisch in der Größe skaliert wird (was bei der Galerie aber nicht der Fall ist).

(u.a. vgl. Stack Overflow 2012)
Stack Overflow 2012, „Change img src in responsive designs?“, Abruf am 23.06.2013, http://stackoverflow.com/questions/10439382/change-img-src-in-responsive-designs
    // ähnlich bei: http://stackoverflow.com/questions/10439382/change-img-src-in-responsive-designs 
function resizeImages(divId, searchString, replaceString, windowWidth) { 
 
        var width = (window.innerWidth || document.documentElement.clientWidth); // Breite des Fenster (bzw. viewport) 
 
        // je Bild innerhalb des Divs (der Galerie) 
        $("#"+divId+" img").each(function() { 
 
                var oldSrc = $(this).attr('src'); // src-Attribut in img 
 
                if (width >= windowWidth) 
                        $(this).attr('src', oldSrc.replace(searchString, replaceString)); // mit großem Bild ersetzen 
                else 
                        $(this).attr('src', oldSrc.replace(replaceString, searchString)); // zurück zum kleinen Bild (umkehren) 
        }); 
}

Die Funktion resizeImages() wird jeweils nach dem vollständigen Laden der Seite und bei Größenänderungen aufgerufen:

<script> 
		resizeWidth = 820; // entspricht dem Umbruchpunkt der Media Query 
 
	// nach dem Laden der Seite: Bilder skalieren, d.h. größere Bilder laden in der Desktop-Version 
	$(document).ready(function() { 
		resizeImages('galerie', 'person_sehr_klein', 'person_klein', resizeWidth); 
	}); 
 
	// bei Änderung der Fenstergröße ggf. Bilderwechsel 
	$(window).resize(function() { 
		resizeImages('galerie', 'person_sehr_klein', 'person_klein', resizeWidth); 
	}); 
 
</script> 

An resizeImages() wird die ID des umgebenden Galerie-DIVs („galerie“), die Namensbestandteile der kleinen („person_sehr_klein“) und größeren Bilder („person_klein“) sowie die Breite des Umbruchpunkts (820) übergeben. Die Funktion ermittelt zunächst die aktuelle Größe des Fensters und prüft danach alle Bilder (img), die sich in #galerie befinden. Ist der Umbruchpunkt erreicht oder überschritten, wird das src-Attribut jedes Bildes auf die größere Version geändert (und das Bild vom Browser geladen; und umgekehrt). Im Wesentlichen findet also ein Bildertausch je nach Fenstergröße statt. Die nächsten zwei Abbildungen zeigen die Galerie bei 900px und 500px:

Prototyp C / Galerie bei 900px Prototyp C / Galerie bei 500px

Vorheriges Kapitel Nächstes Kapitel