Ein flexibles, SEO-gerechtes Layout

Nachdem ich kürzlich darüber schrieb, ob ein flexibles oder statisches Layout besser wäre, will ich jetzt mit etwas praktischerem fortfahren und die Umsetzung des Grundgerüsts einer dynamischen Seite mittels CSS erläutern. Dass ich keine Tabellen zur Erstellung des Layouts einsetzen will, muss ich hoffentlich nicht erklären.

Einfaches Drei-Spalten-Layout

Ich persönlich arbeite gern mit float. Man könnte zwar auch mit absoluter Positionierung arbeiten, aber mein Fall ist das eigentlich nicht. Für die Umsetzung eines typischen Drei-Spalten-Layouts könnte man einfach die Navigation links floaten lassen, eine Sidebar auf der rechten Seite und der Inhalt bleibt in der Mitte und füllt den übrig gebliebenen Platz aus. Schauen wir uns zuerst den HTML-Code an:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
<head>

<title>Test</title>
<style type="text/css">
	@import url(style.css);
</style>

</head>
<body>

<div id="page">
	<div id="header"></div>
	<div id="navigation"></div>
	<div id="sidebar"></div>
	<div id="content"></div>
	<div id="footer"></div>
</div>

</body>
</html>

Die einzelnen Bereiche der Seite (Header, Footer, Navigation, Sidebar, Content) sind mit IDs gekennzeichnet und werden in der CSS-Datei über diese ID angesprochen:

/* Viele Elemente haben browserabhängig vordefinierte Abstände nach außen und
   nach innen, mit dieser Anweisung wollen wir diese entfernen. */
* {
	margin: 0;
	padding: 0;
}

/* Dieses Element umschließt die gesamte Seite, um sie auf eine bestimmte Breite
   zu bringen. Block-Elemente wie dieses nehmen automatisch die volle zur
   Verfügung stehende Breite an, die wir hier aber durch Minimum- und Maximum
   einschränken wollen. */
div#page {
	min-width: 700px;
	max-width: 1000px;
	/* Der Abstand von 10 Pixel gilt für oben und unten, "auto" für links
	   und rechts - dadurch wird das Element horizontal zentriert. */
	margin: 10px auto;
	background-color: #ccc;
}

/* Der Header beinhält zumeist den Titel der Website und ist hier nur der
   Vollständigkeit halber aufgeführt. */
div#header {
	height: 100px;
	background-color: yellow;
}

/* Die Navigation wird aus dem Textfluss genommen und ganz nach links geschoben,
   außerdem wird eine feste Breite vorgegeben. */
div#navigation {
	float: left;
	width: 150px;
	height: 500px;
	background-color: maroon;
}

/* Die Sidebar wird aus dem Textfluss genommen und ganz nach rechts geschoben,
   außerdem wird eine feste Breite vorgegeben. */
div#sidebar {
	float: right;
	width: 200px;
	height: 500px;
	background-color: green;
}

/* Der Inhaltsbereich nimmt automatisch die zur Verfügung stehende Breite ein,
   wird aber durch das Margin so weit vom linken und rechten Rand weggedrückt,
   wie Navigation und Sidebar breit sind. */
div#content {
	height: 500px;
	margin: 0  200px 0 150px;
	background-color: navy;
}

/* Der Footer hat wie der Header eher Vollständigkeits-Charakter. Wichtig ist
   hier aber das "clear", damit er auf jeden Fall erst unter Navigation und
   Sidebar erscheint, sollte der Content mal kürzer sein als eines von beidem. */
div#footer {
	clear: both;
	height: 50px;
	background-color: orange;
}

Die Höhenangaben dienen zumeist nur dazu, sich einen Eindruck vom Ergebnis machen zu können. Durch die farblichen Hintergründe kann man die einzelnen Teile auch gut voneinander unterscheiden, das Ergebnis sieht so aus (klicken, um das Beispiel als eigenständige Seite zu sehen):

Ein Unterschied zur Umsetzung mit Tabellen wird hier deutlich: Die Container für die drei nebeneinander befindlichen „Spalten“ sind nicht zwangsläufig gleich hoch. Zwar wird die Höhe im Beispiel fest vorgeschrieben, in der Realität aber richtet sie sich zumeist nach dem Inhalt. Mit „Faux Columns“ gibt es eine Möglichkeit, zumindest den Anschein zu erwecken, als seien alle Container gleich hoch und es gibt auch verschiedene Methoden, wie man die Höhe tatsächlich erzwingen kann, aber das werde ich vielleicht in einem anderen Artikel näher erläutern.

SEO-gerechtes Drei-Spalten-Layout

Mit der eben genannten Art, ein flexibles Drei-Spalten-Layout zu erstellen, gibt es aber ein Problem und damit kommen wir auf einen Punkt zu sprechen, der schon im Titel dieses Artikels erwähnt wird. Vielleicht habt ihr euch auch schon gefragt, was das denn überhaupt mit Suchmaschinenoptimierung zu tun haben soll und das will ich euch jetzt beantworten.

Stellt euch vor, es gäbe ein Textdokument über Rohrzangen. In dem Fall käme das Wort „Rohrzange“ wohl mehrmals im Text vor, insbesondere am Anfang (z.B. im Titel). Ein Wort, um das es eher nicht oder nur am Rande geht, wie z.B. „Säge“, wird, wenn überhaupt, vermutlich erst später im Text erwähnt. Deshalb speichern die meisten Suchmaschinen die Position ab, die ein Wort in einem Dokument hat, und je weiter hinten es auftaucht, desto weniger Gewicht hat es in Bezug auf das Dokument. Dass auch Google auf die Position achtet, kann man im Abschnitt 4.2.5 der Ausarbeitung „The Anatomy of a Search Engine“ von Sergey Brin und Lawrence Page nachvollziehen – in dieser Arbeit erklären sie ihren Google-Prototypen.

Was hat das jetzt mit unserem Layout zu tun? Schaut man sich einmal den HTML-Code an, so fällt auf, dass der Content-Bereich, also der, in dem die eigentlichen Inhalte stehen, vor dem Footer das vorletzte Element ist. Alle Wörter, die in Header, Navigation oder Sidebar vorkommen, werden also eine kleinere Position haben und damit höher gewichtet werden, als der eigentliche Inhalt. Zwar könnte ich mir vorstellen, dass Google inzwischen so intelligent ist und Seiten mit selber Domain vergleicht, um herauszufinden, welcher Bereich den eigentlichen Inhalt darstellt und diesen so höher gewichten kann, aber dazu ist mir nichts bekannt und man wäre zumindest auf der sicheren Seite, wenn der Inhalt noch vor den seitlichen Spalten im Code auftauchen würde.

Doch da fangen die Probleme an. Soll der Content-Bereich vor den Sidebars sein, muss er zwangsläufig per float an eine Seite befördert werden (es sei denn, man realisiert das Layout z.B. mit absoluter Positionierung). Die Sidebars wären dann daneben. Hätten alle Spalten eine fest vorgegebene Breite, so könnte man sie nach belieben umsortieren, wie es im Artikel „Any Order Columns“ beschrieben wird. Dabei müssen alle Elemente in die selbe Richtung floaten und mittels teils positivem und teils negativem Margin ändert man die visuelle Reihenfolge. Haben z.B. Inhalte und Sidebars feste Breitenangaben im Prozentformat, so wäre die Seite flexibel in der Breite und diese Technik könnte eingesetzt werden.

Ich will aber einen Schritt weiter gehen und wie im Beispiel oben nur den Inhalt flexibel gestalten, Navigation und Sidebar sollen jeweils eine feste, nicht-prozentuale Breite haben. Ein Element, das per float an den Rand befördert wird, nimmt automatisch den gerade so nötigen Platz ein und nicht, wie ein normales Block-Element, den gesamten zur Verfügung stehenden. Soll der Content also die volle Breite einnehmen, muss diese auf 100% gesetzt werden. Aber dann nimmt das Element wiederum die volle Breite des Elternelements an, ungeachtet dessen, ob noch weitere floatende Elemente darin sind.

Eine Lösung für dieses Problem habe ich vor einiger Zeit mal flüchtig in einem Buch über CSS gesehen und als ich diesen Blog gestaltet habe, rief ich es mir nochmal ins Gedächtnis zurück. Anhand eines zweispaltigen Layouts lässt es sich einfach erklären: Inhalt und Sidebar stehen nacheinander im HTML-Code und um beide herum ist ein Div-Container. Dieses Wrapper-Element hat nach rechts einen Abstand, der der Breite der Sidebar entspricht. Diese floatet zur rechten Seite und wird mit negativem rechten Abstand in eben diese Lücke zwischen Wrapper und Seitenrand gezogen. Nun hat der Inhalt die volle Breite des Wrapper-Elements für sich allein, floatet nach links und kann eine horizontale Ausdehnung von 100% bekommen.

Zur Verdeutlichung seht ihr hier den wesentlichen Teil des HTML-Codes und eine kleine Skizze, damit das Grundprinzip klar ist, bevor es zum kompletten Beispiel anhand eines Drei-Spalten-Layouts geht:

<div id="wrapper">
	<div id="content"></div>
	<div id="sidebar"></div>
</div>

Im Falle von drei Spalten braucht man ein zweites Wrapper-Element, wie man im Code leicht sieht:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de">
<head>

<title>Test</title>
<style type="text/css">
	@import url(style.css);
</style>

</head>
<body>

<div id="page">
	<div id="header"></div>
	<div id="outerwrapper">
		<div id="innerwrapper">
			<div id="content"></div>
			<div id="navigation"></div>
		</div>
		<div id="sidebar"></div>
	</div>
	<div id="footer"></div>
</div>

</body>
</html>

Zwar sind verglichen mit der einfachen Ursprungsversion zwei Wrapper-Elemente hinzugekommen, dafür aber ist der Content noch vor Navigation und Sidebar. Man könnte die beiden seitlichen Spalten auch tauschen, müsste dann aber etwas die Styles anpassen, die wie folgt aussehen:

/* Viele Elemente haben browserabhängig vordefinierte Abstände nach außen und
   nach innen, mit dieser Anweisung wollen wir diese entfernen. */
* {
	margin: 0;
	padding: 0;
}

/* Dieses Element umschließt die gesamte Seite, um sie auf eine bestimmte Breite
   zu bringen. Block-Elemente wie dieses nehmen automatisch die volle zur
   Verfügung stehende Breite an, die wir hier aber durch Minimum- und Maximum
   einschränken wollen. */
div#page {
	min-width: 700px;
	max-width: 1000px;
	/* Der Abstand von 10 Pixel gilt für oben und unten, "auto" für links
	   und rechts - dadurch wird das Element horizontal zentriert. */
	margin: 10px auto;
	background-color: lightgrey;
}

/* Der Header beinhält zumeist den Titel der Website und ist hier nur der
   Vollständigkeit halber aufgeführt. */
div#header {
	height: 100px;
	background-color: yellow;
}

/* Das äußere Wrapper-Element enhält Content, Navigation und Sidebar. Außerdem
   hält es Abstand zu den Seiten, um dort für Navigation und Sidebar Platz zu
   schaffen. */
div#outerwrapper {
	/* Breite der Navigation. */
	margin-left: 150px;
	/* Breite der Sidebar. */
	margin-right: 200px;
}

/* Das innere Wrapper-Element enthält Content und Navigation. Es floatet neben
   der Sidebar (in die entgegengesetzte Richtung) und nimmt den vollen Platz
   innerhalb des äußeren Wrappers ein. */
div#innerwrapper {
	float: left;
	width: 100%;
}

/* Der Inhalt hat eine Breite von 100% und nimmt damit den gesamten Platz vom
   inneren Wrapper-Element ein. */
div#content {
	float: right;
	width: 100%;
	height: 500px;
	background-color: navy;
}

/* Die Navigation ist ebenfalls im inneren Wrapper und floatet zur anderen
   Seite, so dass die Navigation neben dem Inhalt am Rand des Wrappers liegen
   könnte (wenn man die Breite des Inhalts mal außer acht lässt). */
div#navigation {
	float: left;
	/* Der negative Abstand nach links befördert die Navigation aus beiden
	   Wrappern hinaus. */
	margin-left: -150px;
	width: 150px;
	height: 300px;
	background-color: maroon;
}

/* Die Sidebar ist neben dem inneren Wrapper und floatet zur anderen Seite, um
   ähnlich wie die Navigation am Rand des Elternelelements zu liegen. */
div#sidebar {
	float: right;
	/* Der negative Abstand nach rechts befördert die Sidebar aus dem
	   Wrapper hinaus. */
	margin-right: -200px;
	width: 200px;
	height: 400px;
	background-color: green;
}

/* Der Footer hat wie der Header eher Vollständigkeits-Charakter. Wichtig ist
   hier aber das "clear", damit er auf jeden Fall erst unter Navigation und
   Sidebar erscheint, sollte der Content mal kürzer sein als eines von beidem. */
div#footer {
	clear: both;
	height: 50px;
	background-color: orange;
}

Das Ergebnis sollte genau so aussehen, wie unser erstes Beispiel oben:

Variante mit Faux Columns

Auch wenn ich die Problematik der gleich hohen Spalten eigentlich in einem anderen Artikel behandeln möchte, so will ich hier doch eine Möglichkeit beschreiben, die ebenfalls in die Kategorie „Faux Columns“ fällt. Wenn man die eben vorgestellte Variante nutzt, um eine flexible Seite zu erstellen und außerdem Navigation und Sidebar einen einfarbigen Hintergrund ohne Rand bekommen sollen, so könnte man dem äußeren Wrapper statt Abständen zur Seite einen Rahmen geben.

Außerdem wird es hier nötig, den äußeren Wrapper dazu zu zwingen, so hoch zu sein, wie seine Inhalte – da diese aus dem Textfluss herausgenommen wurden, ist das nicht automatisch gegeben. Der wesentliche Teil des HTML-Codes ändert sich wie folgt:

<div id="page">
	<div id="header"></div>
	<div id="outerwrapper">
		<div id="innerwrapper">
			<div id="content"></div>
			<div id="navigation"></div>
		</div>
		<div id="sidebar"></div>
		<div class="clear"></div>
	</div>
	<div id="footer"></div>
</div>

Im Normalfall bekommt der Rahmen links bzw. rechts des äußeren Wrappers jetzt die selbe Hintergrundfarbe, wie Navigation bzw. Sidebar, während diese keinerlei Hintergrund mehr definieren, damit der Rahmen immer durchscheint (und man beim Anpassen der Farbe nur eine Stelle ändern muss). Da ich aber den Effekt deutlich machen will, gebe ich dem Rahmen eine andere Farbe und so sieht man immer noch, wie hoch Navigation und Sidebar tatsächlich sind:

div#outerwrapper {
	/* Beseitigt einen Bug vom IE7 */
	min-height: 0;
	/* Breite der Navigation. */
	border-left: 150px solid red;
	/* Breite der Sidebar. */
	border-right: 200px solid lime;
}

div.clear {
	clear: both;
	height: 0;
}

In rot sind auch auch hier die wesentlichen Änderungen gegenüber dem vorigen Beispiel. Vielleicht fragt sich der ein oder andere, was es mit dem Bugfix für den Internet Explorer 7 auf sich hat – doch auch das ist ein anderes Thema, das ich sicher noch ansprechen werde. Das ist auch nur deswegen drin, damit Personen mit eben diesem Browser das Beispiel auch korrekt sehen können:

Letzte Hinweise

Abschließend will ich noch hinzufügen, dass Padding, also der Abstand eines Elementes nach innen, auf die Breite draufgeschlagen wird. Bekommt der Inhalt also diesen inneren Abstand, dann ist er breiter als 100%. In dem Fall muss man entweder die Maße der seitlichen Spalten anpassen oder man benötigt einen weiteren Container im Content, der per Margin oder Padding für den zusätzlichen Abstand sorgt. Da ich mit meinen Beispielen aber vorrangig die Grundprinzipien darstellen wollte, habe ich auf derartige Details verzichtet.

Das war jetzt eine Menge Stoff, aber ich hoffe, dass ich es halbwegs verständlich rüberbringen konnte. Wenn es noch Unklarheiten gibt oder ihr andere CSS-Techniken kennen lernen wollt, dann schreibt es mir in die Kommentare und mit ein bisschen Glück bekommt ihr eine Antwort.

Tags: ,

1 Pingback

  1. Buch: Fortgeschrittene CSS-Techniken - rattlab.net 13. September 2008 um 22:33

3 Antworten

  1. Hey erstmal möchte ich dir zu deinem sehr gelungenen Artikel gratulieren! Ich habe sehr lange gesucht bis ich einen so gut und verständlich geschriebenen Artikel zu diesem Thema gefunden habe, der sich wirklich nur auf das Wichtigste konzentriert!

    Ich habe nun aber ein Problem, mit meiner so layouteten Seite. Und zwar scheint es ein Redering-Problem im IE7 zu geben, ich bin allerdings nicht sicher ob das an deinem Layout oder meinem Code liegt. Vielleicht haste sowas ja schonmal gesehen. Der Rahmen vom Content verschmilzt mit dem Rahmen der rechten Sidebar:
    http://share.matthias-balke.de/pics/ie7bug2.PNG

    Matthias

  2. ex-ratt says:

    Jau, liegt tatsächlich an meinem Code. Genau das gleiche Problem hatte ich auch mit dieser Seite hier, hatte das aber gelöst und zum Zeitpunkt des Schreibens schon irgendwie vergessen. Hab gerade mal ein bisschen rumprobiert und kann dir eine Lösung anbieten.

    Der Internet Explorer hat ein Problem damit, dass die Sidebar zur Seite floatet und will sie nicht weiter nach außen rücken. Man könnte jetzt das negative Margin also noch größer machen (vom Betrag her) und es würde sich nichts ändern. Damit die Seite vernünftig aussieht, müssen zwei Dinge gemacht werden:
    1. die float-Eigenschaft wegmachen – da die Sidebar (zumindest in meinem Beispiel) der letzte Inhalt im Wrapper ist und dieser danach zu Ende ist, ist das einfach machbar
    2. die margin-Eigenschaft umschreiben und einen Abstand nach links festlegen (auf auto)

    Ausgehend von meinem Beispiel oben (kurz vor der Überschrift „Variante mit Faux Columns“) ändert man die Sidebar-Eigenschaften also:

    div#sidebar {
    margin-right: -200px;
    margin-left: auto;
    width: 200px;
    height: 400px;
    background-color: green;
    }

    Versuch das mal so :)

  3. Herzlichen Dank für die schnelle Hilfe, das scheint gut zu funktionieren!