Minz schaut über den Tellerrand

CSS - Höhe berechnen und Zusammenfallende Ränder

8/3/2004

...oder: das wundersame Schrumpfen von CSS Behältern!

Bei diesem Artikel handelt es sich um eine Übersetzung aus dem englischen. Folgende Namenskonventionen, die ich der Übersetzung der W3C Empfehlungen entnommen habe, sind hierbei zu beachten:
margin = Ränder
padding = Polsterbereich
border = Rahmen
normal-flow = normaler Fluss
Ein outer margin edge wäre demzufolge die äußere Randkante.

Manch einem mag es geläufig sein, dass ich nebenbei als Co-Trainer eines CSS-Workshops bei der IWAHWG beschäftigt bin. Diese Woche wurden zwei der Workshop-Teilnehmer mit ein und demselben Problem konfrontiert. Dieses Problem war Anlass für untenstehende Ausführungen.

Wer regelmäßig mit CSS arbeitet, ist bestimmt schon des öfteren über das hier beschriebene Verhalten von CSS Behältern gestolpert. Und genauso wie ich, haben bestimmt viele eine Lösung gefunden um damit umzugehen. Doch das Verständnis für das Verhalten, das Wie und Warum bleibt bei solchen Workarounds oft auf der Strecke.

Hier zum ersten Teil des Problems, aus Gründen der Übersichtlichkeit auf ein Minimum reduziert. Folgendes HTML Fragment gilt es zu betrachten:

<div>

<p>Dies ist ein Paragraph innerhalb eines <code>div</code>-Behälters.</p>
</div>

An dieses Fragment sind folgende CSS Stile geknüpft:

div {

background-color: #3C75AE;
color: #fff;
margin-top: 10px;
}
p {
margin-top: 20px;
margin-bottom: 20px;
border: 1px solid #EB6B0E;
}

Ich bin mir ziemlich sicher, dass auf den ersten Blick die meisten (mich eingeschlossen) folgende Darstellung im Broswer erwarten würden:

Überraschenderweise zeigen die meisten modernen Webbrowser jedoch dieses an:

Zum Nachvollziehen gibt es hier den oben stehenden Code als Beispiel 1.

Wodurch wird dieses seltsame Verhalten ausgelöst? Zwei wesentliche Aspekte des CSS Formatierungsmodells spielen hierbei eine Rolle. Einer davon ist das Zusammenfallen von vertikalen Rändern (englisch: margin-collapsing.) Dies bedeutet, dass CSS2-konforme Browser die senkrechten Ränder (also margin-top, margin-bottom) benachbarter Elemente zusammenfallen lassen, anstatt sie zu addieren. Im Endergebnis bedeutet dies, dass der größere Abstand gewinnt und den kleineren sozusagen "verschluckt".

Für unser oben stehendes Beispiel heißt das, dass die obere Rahmenkante unseres div-Behälters 20 Pixel und nicht 30 Pixel von einem vorangehenden Element oder des umschliessenden Elements entfernt ist (vorausgesetzt natürlich, dass keines dieser Elemente einen unteren Rand hat welcher größer ist als 20px, was in unserem Beispiel jedoch nicht der Fall ist. Weiterhin sei hiermit angenommen, dass unser div Element das erste und einzige untergeordnete Element von body ist.) Hier wird also, wie bereits erwähnt der kleinere Rand zugunsten des größeren eliminiert. Illustriert sieht dies folgendermaßen aus:

Soweit so gut, aber warum ist der Paragraph denn nicht 20 Pixel von der oberen äußeren Rahmenkante des div Elements entfernt, wie in Abbildung 1 dargestellt? Warum steht der Rand des Paragraphen oben (und unten) über?

Bevor wir zu einer Antwort auf diese Fragen kommen habe ich eine Illustration des CSS Box-Modells angefertigt. Sie zeigt jedoch lediglich den vertikalen Teil, denn darum geht es hier ja hauptsächlich. Zusätzlich habe ich die englischen Namen mit eingefügt, als Referenz sozusagen:

Diagramm des CSS Box-Modells

Die Antwort auf oben gestellte Fragen leitet sich von der Tatsache ab, wie die Höhe (englisch: height) eines Blockebenen-Elements (englisch: block-level element) in CSS berechnet wird. Wird für solch ein Element im Stylesheet keine Höhenangabe definiert, dann wird dieser Wert auf auto gesetzt. auto ist der Ausgangswert für Blockebenenelemente. Per Definition ist damit die Höhe unseres div-Elements die Entfernung von der äußeren oberen Rahmenkante bis zur äußeren unteren Rahmenkante des Paragraphen. Sämtliche vertikalen Ränder des Paragraphen ragen also über das div-Element hinaus, sie stehen über. Die nächsten zwei Bilder versuchen dies zu veranschaulichen. Das erste zeigt die gesamte Box des Paragraphen, während das zweite die erwähnte Berechnung der Höhe des div-Elements dokumentiert.

Wie kann dann aber das Zusammenfallen des oberen Randes vermieden werden? Angenommen wir möchten, dass unser Paragraph 20 Pixel vom oberen Rand des div-Elements enfernt ist. Wie wäre dies zu bewerkstelligen? Die Antwort auf diese Frage liegt bereits in der Fragestellung selbst. Wir müssen die Höhe, bzw. die Höhenberechnung unseres divs verändern, und zwar in dem wir entweder einen Rahmen (englisch: border) oder einen Polsterbereich (englisch: padding) hinzufügen. Probieren wir folgende Änderungen unseres CSS-Stils:

div {

background-color: #3C75AE;
color: #fff;
margin-top: 10px;
padding-top: 1px;
padding-bottom: 1px;

}

Dieses kleine Codefragment verändert die Verfahrensweise der Höhenberechnung unseres div-Elements vollkommen (wobei die Höhe des Elements nach wie vor auto ist). Die Höhe unseres div-Elements ist nun die Entfernung von der äußeren oberen Randkante bis zur äußeren unteren Randkante des Paragraphen. Das gleiche wäre passiert, hätten wir anstatt eines Polsterbereiches einen Rahmen hinzugefügt. Siehe untenstehende Illustration oder aber das Beispiel 2.

Weiterführendes Beispiel, diesmal jedoch mit einem floatenden Element!

Die folgenden Abschnitte schildern vereinfacht das Problem, das während unseres CSS Workshops auftrat. Als Ausgangspunkt sei folgendes HTML-Fragment gegeben:

<body>

<div id="verweise">
A list of links
</div>
<div id="inhalt">
...Inzeiliger anonymer Text....
</div>
</body>

..und für die Präsentation folgende Stylesheets:

body {

font: 100%/1.5 Georgia, "Times New Roman", Times, serif;
}

div#verweise {
float: right;
width: 50%;
margin-top: 0;
background-color: #EB6B0E;
color: #fff;
}

div#inhalt {
background-color: #3C75AE;
color: #fff;
margin-top: 30px;
border: 1px solid #3C75AE;
}

Wenn wir uns nun das Resultat dieser Zeilen in verschiedenen Internetbrowsern ansehen, erhalten wir durchaus unterschiedliche Darstellungen:

Mozilla Darstellung
Mozilla 1.7

Opera Darstellung
Opera 7.5

Internet Explorer Darstellung
Internet Explorer 6

Wer möchte, kann das Verhalten seines eigenen Browsers überprüfen. Hier ist Beispiel 3.

Ganz toll, oder? Wahrlich einer der Gründe warum CSS ein Garant für graue Haare ist :)

Sehen wir uns aber einmal unser HTML-Fragment und die Stile in Ruhe an und ziehen die CSS-Empfehlungen des W3C zu Rate, dann wird ganz schnell deutlich, dass Mozilla das Beispiel korrekt umsetzt. Unter bestimmten Bedingungen trifft das auch auf die Interpretation von Opera zu (warum das so ist, erkläre ich später). Internet Explorer (Überraschung!) liegt hier falsch.

Meine allererste Vermutung war jedoch genau das Gegenteil. Was Mozilla hier zeigt kann nicht korrekt sein! Ich ging von einer eindeutigen Verletzung der Float-Regel Nummer 8 aus, welche besagt:

Eine Floating-Box muss so hoch wie möglich platziert werden.

Also muss doch Opera richtig liegen, und selbst der IE kommt der Sache recht nahe. Dieser zweite Gedanke allein sollte bei jedermann sämtliche Alarmglocken schrillen lassen! Schauen wir also einmal, welche weiteren Anhaltspunkte sich finden lassen. Hier sticht dann Float-Regel Nummer 4 ins Auge:

Die äußere obere Kante einer Floating-Box darf nicht höher sein als die oberste Kante des umschließenden Blocks.

In unserem Falle wäre der umschließende Block body. Und wir landen wieder bei der Frage, wo ist die obere Kante, bzw. was ist die Höhe von body? Die Stile enthalten lediglich eine font Deklaration. Dies bedeutet, dass die durch die CSS-Regeln vorgegebenen Anfangswerte für Rand, Polsterbereich und Rahmen wären in diesem Falle also 0, 0 und none was gleichbeutend ist mit kein Rand, kein Polsterbereich und kein Rahmen.

Wenn wir also berücksichtigen was wir im ersten Beispiel gelernt haben, dann heißt das, dass die Höhe von body nun die Entfernung von der äußeren oberen Rahmenkante zur äußeren unteren Rahmenkante seiner untergeordneten, im normalen Fluss befindlichen Elemente (in unserem Falle, der Inhalts-div) ist, während die Ränder dieser untergeordneten Elemente darüber hinausragen.

Wie kommt es dann, dass Opera die ganze Geschichte unterschiedlich darstellt und sich trotzdem korrekt verhält? In diesem Falle muss man sich vor Augen halten, dass die meisten Browser von Haus aus bereits eigene "Browserstylesheets" implementiert haben. Diese Stylesheets regeln zum Beispiel die Anzeige von Hyperlinks oder Schriftarten und -größe auf ungestyleten HTML-Seiten (aus diesem Grund sind nämlich Verweise/Links, wenn nichts anderes angegeben, in den meisten Fällen blau und unterstrichen.) Zusätzlich wird in diesen Browserstylesheets ein Rand und ein Polsterbereich für das body-Element gesetzt.

Da wir in unseren Stilen weder Rand noch Polsterbereich definiert haben, werden unsere durch die CSS-Regeln vorgegebenen Anfangswerte durch das Browserstylesheet überschrieben. Der Knackpunkt hierbei ist, dass Opera andere Stile benutzt als Mozilla oder der Internet Explorer. Bei Opera wird definiert:

body {

margin: 0;
padding: 8px;
}

Mozilla und Internet Explorer geben ihrerseits folgende Werte vor:

body {

margin: 8px;
padding: 0;
}

Nur ein kleiner Unterschied, aber mit sehr großer Wirkung auf das Aussehen der Seite. Machen wir uns die Mühe und kopieren Opera's Stile in unser Beispiel:

body {

font: 100%/1.5 Georgia, "Times New Roman", Times, serif;
margin: 0;
padding: 8px;

}

Da es jetzt einen Polsterbereich gibt, ändert sich die Höhe von body. Berechnet wird nun die Entfernung von der äußeren oberen Randkante zur äußeren unteren Randkante seines untergeordneten, sich im normalen Fluss befindlichen Elements.

Auch dieses letzte Beispiel gibt es in "echt". Beispiel 4.

Wem die hier dargestellten Illustrationen zu klein sind, ich habe alle noch einmal in höherer Auflösung auf einer eigenen Seite bereitgestellt.

Empfohlenes Lesematerial

Weitestgehend sind hier englischsprachige Verweise aufgeführt, aber wer dieser Sprache mächtig ist, sollte die folgenden Empfehlungen unbedingt ansehen.

  1. Andy Budd: No margin for error
  2. Eric Meyer: Cascading Style Sheets, The Definitive Guide - Second Edition
  3. CSS 2 Spezifikation: 10.6 Höhen und Ränder berechnen.

Kommentare

Jens Grochtdreis:

Danke für die Übersetzung. Ich fand es schade, daß Du als Deutscher unbedingt einen solchen Artikel auf Englisch verfaßt. Schließlich gibt es schon genügend richtig gute englischssprachige CSS-Seiten, aber leider nur wenige gute deutschsprachige. Habe den Artikel auch gleich zweimal gebloggt :-)

Ich finde allerdings die Übersetzung von margin und padding nicht gut. Mag das W3C dies auch tausendmal tun. Ich pflege immer für margin vom Außenabstand und für padding vom Innenabstand zu sprechen und schreiben. Da hat man gleich die Eigenart dieser Eigenschaft vor Augen. Am besten ist es allerdings, gleich bei den englischen Begriffen zu bleiben, schließlich verwendet man die auch in der Erstellung des CSS. So spart man sich das hin-und-her-Denken.

Ich bin mal auf Deinen nächsten Artikel gespannt.

Grüße aus Mainz,
Jens

Abgegeben am 8/3/2004 8 um 24:50 AM

Alex Weber:

in welchem browser soll dieser fehler zu sehen sein. In keinem meiner Browser kann ich den Fehler sehen, weder im IE, Opera, NS, Mozilla, NS, Firefox und selbst im Konquerer nicht.

Abgegeben am 8/3/2004 3 um 43:44 PM

Minz Meyer:

@Jens
ja...vielen Dank. Ehrlich gesagt habe ich mich aus den von Dir erwähnten Gründen echt schwer getan mit der Übersetzung.
Ich finde die Übersetzungen für margin und padding auch nicht glücklich, aber wenn ich eine Referenz auf Edition W3C setze, finde ich schon, dass der Syntax übereinstimmen sollte. Vielleicht sollte man den Herrn Mintert mal drauf ansprechen. Wenn jedoch jeder eine eigene Übersetzungs-Variante benutzt, kommen wir nie auf einen grünen Zweig.

@Alex
von welchem Fehler sprichst Du?

Abgegeben am 8/3/2004 1 um 19:46 PM

Jens Grochtdreis:

@Thilo: Da magst Du ja recht haben, daß es nicht schlecht ist, bei dem Verweis auf die deutsche W3C-Übersetzung in deren Terminus zu bleiben. Trotz alledem macht in meinen Augen - und Dir scheint es ähnlich zu gehen - diese Übersetzung die Vermittlung schwer. Und da Dein Hauptanliegen ja die Vermittlung ist (wie bei mir in der CSS-FAQ), solltest Du Dich einer verständlichen Sprache bedienen. Und ob ich zu Herrn Mintert in diesem Falle durchdringe, wage ich ja leider zu bezweifeln.
Bin schon auf weitere Artikel gespannt.

Abgegeben am 8/3/2004 1 um 35:30 PM

Marc Humer:

Ich möchte mich ganz herzlich bedanken - der Umstand mit dem margin und padding bei Opera (die 0/8 Pixel-Geschichte) hat mich graue Haare gekostet ohne Ende - wäre ich im Leben nicht drauf gekommen - zumindest nicht in diesem :o)

Jetzt wird alles korrekt angezeigt, lediglich ein kleines PHP-Skript stellt die Höhe des Body auf 98% bei Netscape (sonst 100%), damit die Scrollbalken dort bleiben, wo sie hingehören - im Reich des unsichtbaren.

Wegen der Benennung von margin und padding möchte ich sagen, daß ich mit beiden deutschen Begriffen (Polster, Innenabstand) als auch mit dem englischen Begriff selbst klarkomme. Ich denke, der Punkt ist weniger die Bennenung als die korrekte Umsetzung seitens der Browser (der Grund, warum ich hier gelandet bin :)

Denn dann, wünsche weiterhin viel Spass und nochmals danke :)

Marc Humer

Abgegeben am 9/15/2004 um 40:54 PM

Spicken Webmaster:

Toller Artikel. Kann ich gut gebrauchen, da ich gerade meine Seite erneuere. Bitte mehr davon!

Abgegeben am 10/3/2004 um 33:24 PM

Vitaly Friedman:

Vielen Dank für deine Übersetzung! Sehr hilfreich und professionell gemacht! Ich bin gespannt auf deinen nächsten Artikel.

Abgegeben am 7/22/2005 um 51:50 PM