Einschließen von Floats ohne zusätzliches Markup

Hinweis:

Der folgende Text ist eine autorisierte deutsche Übersetzung des Artikels "How To Clear Floats Without Structural Markup" von Big John und Holly Bergevin. Die Übersetzer Catherine Gent und Onno K. Gent haben ergänzende Hinweise in [eckige Klammern] gesetzt. Wie auch bei der von Andreas Kalt und Jens Grochtdreis vorgenommenen Übersetzung des Artikels "Float: Die Theorie" haben wir auf eine Übersetzung der Begriffe "float" (schwimmen, schweben) und "clear" (klären) mangels eines wirklich treffenden Begriffs verzichtet.

Wir danken Big John für die Genehmigung zum Übersetzen und den vielen hilfreichen Geistern für die Tips und Ratschläge; ganz besonderer Dank geht an Susanne Jäger für ihre wertvolle Hilfe.

Update 05/07 - aktuelle Links zum Themenbereich:

Zur Startseite dieser Domain

(Diese neue Technik wurde ursprünglich von Tony Aslett von csscreator.com entwickelt)

Bisher gebräuchliche Methoden, Floats einzuschließen

Ein Float innerhalb eines Containers mit sichtbarem Rand oder Hintergrund verschiebt den unteren Rand dieses Containers nicht automatisch so weit, bis dieses Float eingeschlossen ist. Stattdessen wird das Float vom Container ignoriert und hängt aus ihm nach unten wie eine Flagge heraus. Wer lediglich mit dem IE für Windows als Browser vertraut ist, wird sich jetzt am Kopf kratzen und meinen: "Stimmt doch gar nicht!" Tatsächlich, der IE/Win schliesst ein Float "automatisch" innerhalb eines Containers ein, aber nur, wenn der Container eine definierte Größe hat; und in jedem Fall widerspricht es den Spezifikationen des W3C. Dieses unkorrekte Verhalten des IE/Win kann weiterhin auch noch "an- und abgeschaltet" werden, wenn durch überfahren von Links innerhalb des Containers der Linkhintergrund oder verschiedene andere Eigenschaften verändert werden. Ein ziemliches Durcheinander.

Der Möchtegern-IE-Browser Opera 7, schließt ebenfalls ein Float ein, wenn der Container eine feste Größe hat, aber das widerspricht den nachfolgenden Argumenten nicht. Es kann ruhig ignoriert werden, obgleich man durchaus darüber schmunzeln darf. ;-)

Das W3C schlägt vor, ein "cleared"-Element [ein Element mit der Eigenschaft "clear"] als letztes im Container zu benutzen. Dieses soll vom Container erkannt werden und ihn zwingen, dieses "cleared"-Element einzuschließen. Dieses Verfahren wird schon im Artikel Float: The Theory beschrieben [dieser Artikel ist hier in deutscher Übersetzung zu finden]:

"…angenommen man gibt der folgenden Box die Eigenschaft  {clear: both;}. Dann wird der obere Rand der mit "clear" versehenen Box soweit ausgedehnt (unabhängig von der ihm zugewiesenen Größe), bis diese Box unterhalb des floatenden Elements angeordnet werden kann. In anderen Worten wird die folgende Box unter den unteren Rand der vorhergehenden floatenden Box gedrückt und der obere Außenabstand wird vom Browser um den dazu notwendigen Wert entsprechend vergrößert."

Eine solche cleared-Box kann nicht auf der gleichen horizontalen Ebene sein wie eine vorhergehende floatende Box [und sich auch nicht dahinter legen]. Sie muß direkt darunter erscheinen [Der Dokumentenfluß ist wiederhergestellt, somit kann ein folgendes Element erst dann anfangen, wenn das vorhergehende aufhört]. Das Bild zeigt, wie dies aussehen könnte, mit einem das Containerelement darstellenden roten Rand:

Zeigt wie sich eine floatende Box verhalten kann.

Die Standardmethode, mit der ein umschließender Container ein darin befindliches Float-Element anscheinend einschließt, ist, ein vollständiges cleared-Element als Letztes in den Container zu platzieren. Dadurch wird als Effekt die Unterkante des Containers unter das Float gezogen. Somit scheint das Float im Container eingeschlossen zu sein, der Code einer "cleared-Box" sieht normalerweise etwa so aus:

<div> <!-- float container -->
<div style="float:left; width:30%;">
<p>Diverser Inhalt</p></div>
<p>Text ausserhalb des Float Elements</p>
<div style="clear:both;"></div>
</div>

Da dieses "div" nicht floated, muß der Container es erkennen und einschließen; und durch den oberen Außenabstand (welchen der Browser wegen der "clear"-Eigenschaft hinzufügt), zieht dieses div die Unterkante des Containers unter die Unterkante des Floats.

Probleme dieser Methode

Dadurch, daß diese Methode ein zusätzliches Element im Markup erfordert, ist sie alles andere als intuitiv. Eine der wichtigsten Prämissen von CSS ist, aufgeblähten HTML-Code heutiger Durchschnitts-Webseiten zu reduzieren. So ist es nicht ideal, im Markup ein zusätzliches Element einzufügen, damit Floats in ihren Containern bleiben.

Abgesehen davon können in manchen Situationen einige Browser mit bestimmten Arten von clear-Elementen Probleme verursachen. Insbesondere Mozilla ist dafür empfänglich.

Bis jetzt gab es keinen anderen Weg, aber das ist nun vorbei! Dank der Bemühungen von Tony Aslett, Gründer und Betreiber von csscreator.com, kann nun erweitertes CSS genutzt werden, um ein Float-Element in den "guten" Browsern zu clearen, und den IE weiterhin falsch clearen zu lassen. Als Resultat haben wir die Möglichkeit, das ärgerliche clear-Element dem HTML-Code nicht hinzufügen zu müssen. Juchuu!

"Clearing" im 21. Jhdt.

Bei der neuen Methode wird kein clear-Element benötigt. Dies betrifft nicht IE/Win, der einfach weiterhin das Float einschließt (vorausgesetzt, der Container hat eine festgelegte Größe), aber andere Browser benötigen einen Ersatz für dieses Element. Und so wird es gemacht:

Der Gebrauch von :after

Diese CSS2 Eigenschaft ermöglicht es, zusätzlichen Inhalt nach einem Element einzufügen, ohne dass zusätzliches Markup im HTML-Code benötigt wird. Der Inhalt wird in der CSS-Datei angegeben und erscheint auf der Seite, als wäre er ein wirkliches HTML-Element. Solch ein durch :after erzeugter Inhalt ist für manche CSS Eigenschaften nicht erreichbar, darunter "position", "float", Listen- und Tabelleneigenschaften. Allerdings ist die Eigenschaft "clear" zugelassen. Ahnen Sie schon auf was das hinausläuft?

Angenommen man benutzt :after um ein einfaches Zeichen wie "Punkt" einzufügen und weist dann diesem erzeugten Element  {clear: both;}  zu. Das ist alles, was man zur Ausführung benötigt, da aber keiner einen verpfuschten Zeilenabstand am Ende des Containers möchte, benutzt man außerdem  {height: 0;}  und  {visibility: hidden;}  um den "Punkt" unsichtbar zu machen.

.clearfix:after {
    content: "."; 
    display: block; 
    height: 0; 
    clear: both; 
    visibility: hidden;
}

Man beachte, daß  {display: block;}  ebenfalls auf das generierte :after Element angewendet wird, da andernfalls das Element standardmäßig "inline" dargestellt wird und die clear Eigenschaft nicht wirksam wäre. Ebenso benutzte Tonys Methode urprünglich "overflow: hidden;" um den Punkt zu verbergen, aber bedauerlicherweise stellen die neuesten Firefox-Versionen damit den Punkt dar.

Aber was ist mit dem IE?

Da der IE/Win das Pseudoelement :after nicht unterstützt, muß man sich auf seinen "auto-clearing" Effekt verlassen, wobei dieser ja nur dann eintritt, wenn das clear-Element eine definierte Ausdehnung aufweist. In vielen Fällen ist die Angabe einer Höhe oder auch Breite unerwünscht, aber glücklicherweise kommt der Holly-Hack zu unserer Rettung. Dieser Hack zeigt im IE/Win und zwar nur im IE/Win eine einfache 1% Höhe für den Container an. Was bewirkt das? Der IE hat die im Widerspruch zu den W3C Spezifikationen stehende Eigenschaft, alle Boxen zu erweitern bis die Inhalte eingeschlossen sind, unabhängig von vergebenen Werten die kleiner sein können. So wird die 1% Höhe nur bis zu dem benötigten Wert erweitert, um ein Float-Element einzuschließen. Allein das Anwenden eines Größenwertes löst den "auto-clearing" Effekt aus. Cool, wa?

/* Hides from IE-mac \*/
* html .clearfix {height: 1%;}
/* End hide from IE-mac */

Die erste Zeile ist ein CSS-Kommentar mit einem (roten) Backslash direkt vor dem schließenden Tag. Wegen dieses Zeichens ignoriert IE/Mac den schließenden Tag und sieht den Kommentar als noch aktiv an. Somit ignoriert er alles bis zum nächsten Kommentarabschluß. Die letzte Zeile ist ein normaler Kommentar, dessen Schlußtag den IE/Mac wieder zum parsen des folgenden Codes veranlaßt.

Die zweite Zeile besteht aus einem Universalselektor (*), gefolgt von "html" (ebenfalls rot), gefolgt vom Zielelement. Das wählt .clearfix, als Nachfahre von html (zutreffend) wenn "html" in irgendein Element eingebettet ist. IE-Browser benutzen ein unsichtbares und etwas geheimnisvolles Verpackungselement ringsum html, so daß dieser Selector ausschließlich im IE funktioniert. [Die zweite Zeile vom Selectoracle interpretiert: wählt jedes mögliches Element mit einem "class" Attribut aus, welches das Wort "clearfix" enthält, das ein Nachkomme eines html Elements ist, das wiederum ein Nachkomme irgendeines Elements ist. (Letzteres ist im Grunde nicht schlüssig, da html kein Elternelement hat. Alle IEs akzeptieren diese Notation jedoch und interpretieren die nachfolgenden Deklarationen.)] Der IE/Mac muß davon abgehalten werden die [falsche] Höhenangabe zu sehen, da er nicht wie IE/Win die Box einfach vergrößert und dies sonst das Layout zerstören würde.

Als Nebeneffekt verhindert diese festgelegte Größe auch andere erhebliche Float-Bugs im IE/Win. Sollte allerdings die Containerbox einem vorangehenden externen Float folgen, löst die fixe Höhe das proprietäre und kaputte Float-Modell Microsofts aus, also bitte aufpassen!

Guillotine Bug

Es ist nun so, daß der IE ein kleines Problem mit diesem automatisch einschließenden Verhalten hat. Man konnte es kommen sehen, nicht wahr? Ja, IE-Bugs kommen nie allein. Dieser tritt dann auf, wenn das Containerelement dem Float nachfolgende Links enthält. Wenn das so ist und man überfährt mit der Maus die Links, wird das "auto-enclosing" ausgeschaltet und die Unterkante ders Containers springt plötzlich an die Unterkante des Contents. Überfährt man weitere Links, wird die ursprüngliche Ansicht wiederhergestellt. Dieser interessante Effekt wird IE/Win Guillotine Bug genannt. Diejenigen, die den IE/Win benutzen, können mit den folgenden Live-Demos herumspielen und für genauere Erklärungen die IE/Win Guillotine Bug Demoseite ansehen.

Dieser Bug wird nur dann ausgelöst, wenn durch a:hover der Linkhintergrund geändert oder andere Styleveränderungen genutzt werden, wie z.B. padding, margin oder jegliche Schriftänderung der Links. Seltsamerweise löst ein Ändern der Schriftfarbe beim hovern diesen Bug nicht aus.

Die Container sind grau mit grünem Rand, die Floats dunkelbraun mit gelbem Rand. Man beachte, wie der dritte und vierte Link außerhalb der Floats den Guillotine Bug einschalten, und die ersten beiden ihn wieder ausschalten. Dies scheint mit den eigentlichen Textzeilen selbst zusammenzuhängen, so daß alle Links nach den ersten beiden den Effekt anschalten. Links innerhalb des Floats schalten den Effekt alle ab. Nur ein weiteres seltsames buggy Verhalten des IE, Leute, nichts Unübliches.

Float Link
Jeder Link in diesem Float wird den Bug wieder abschalten, so wie die beiden ersten Links außerhalb des Floats. Etwas macht diese beiden Zeilen besonders.
Link
Link
Link
Link
Float Link
Die Links außerhalb des Floats sind hier in einen Absatz eingeschlossen, diesem wurde der Holly-Hack beigefügt. Tschüss, Guillotine Bug!

Link
Link
Link
Link

   

Im zweiten Beispiel wurde um die Links ein Absatz gelegt, und diesem dann durch den Holly-Hack eine Größe zugewiesen. Jedes Blockelement würde hier ebenfalls geeignet sein. Das bedeutet zwar, daß ein weiteres Element benötigt wird, allerdings ist im Gegensatz zu einem clearing-div der Absatz ein semantisch [vertretbares] Element. Textinhalte sollten tatsächlich in semantischen Elementen enthalten sein, und da wir vorausschauenden Codierer unseren Inhalt immer in dieser Art behandelt haben, können wir einfach die .clearfix-Klasse auf ein weiteres Element übertragen.

Ein Wort über Floats in Floats

Aufmerksame Leser werden bemerkt haben, daß die obigen Demos "eingeschlossene" Floats haben, sogar in Opera 7 und Mozilla! Dies verhält sich so, weil diese modernen Browser Floats generell einschließen, wenn das Elternelement ebenfalls ein Float ist. Auch der IE tut es, aber er schließt fälschlich ALLE Elemente ein (nicht nur Floats). Es ist schade, daß der IE es ohne einen Holly-Hack nicht sauber hinbekommt. Zumindest gibt es eine Lösung, was beim IE nicht gerade selbstverständlich ist. Dem IE/Mac wird nachgesagt, einzigartige Probleme mit dem Einbetten von Floats zu haben, und wenn ein Mac-Nutzer diese Problematik ganz austesten und einen klaren Bericht bereitstellen möchte, ist hier eine verlinkte Erwähnung garantiert.

Zusammenfassung

Als erstes wird dieser Code der CSS-Datei hinzugefügt:

.clearfix:after {
    content: "."; 
    display: block; 
    height: 0; 
    clear: both; 
    visibility: hidden;
}

/* Hides from IE-mac \*/
* html .clearfix {height: 1%;}
/* End hide from IE-mac */

Wir fügen jedem Element, welches ein zu clearendes Float beinhaltet und jedem Blockelement welches wir zum Reparieren des Guillotine Bugs einsetzen (wie dem Absatz im Beispiel weiter oben) eine Klasse .clearfix hinzu. Das wars! Es ist nicht perfekt, aber wesentlich besser als ein zusätzliches Dummyelement hinzuzufügen. Man prüfe diese Demo der Lösung:

Dieses Float wird nicht vom umgebenden div eingeschlossen.

Dieser Container hat keine Klasse .clearfix.

   

Beachte, wie dieses Float nicht aus dem Container herausragt, obwohl kein zusätzliches clearing Element verwendet wird.

Dieser Container enthält eine Klasse .clearfix, die je nach Browser den :after Fix oder den Holly Hack anwendet.

IE/Mac schlägt zurück

All dies ist wunderbar, aber unglücklicherweise unterstützt der IE für den Mac weder das "auto-clear" bei Floats noch :after, und bleibt somit beim clearing außen vor. Was ist also zu tun?

Man könnte ganz gefühllos auf den Mac verzichten, sollte aber bedenken, daß viele Leute mit älteren Macs weder Safari noch verschiedene andere moderne Browser nutzen können. Glücklicherweise ist dieser Browser von Microsoft aufgegeben worden und in absehbarer Zukunft werden die Zahlen der IE/Mac Nutzer auf ein Minimum zurückgehen. Man erinnere sich, daß selbst wenn ein Float aus einem Container herauszustehen scheint, dennoch kein Inhalt verdeckt wird. Es sieht eben nur für diese paar Betrachter nicht ganz so gut aus, mehr nicht. Jeder Verfasser wird diese Frage im Hinblick auf seine speziellen Bedürfnisse entscheiden müssen.

Diese Seite beschrieb ursprünglich eine Javascript-Methode um eine Übereinstimmung im IE/Mac zu erzwingen, aber Dank Mark Hadley und Matt Keogh ist es nun möglich, auf dieses häßliche Javascript zu verzichten und mit einem geradlinigen CSS-Fix weiterzumachen. Juchuu!

Zähmung des Float Problems für den IE/Mac

Im Wesentlichen besteht der Fix darin, der Klasse .clearfix ein display: inline-block; anzufügen und diese Eigenschaft vor allen anderen Browsern zu verbergen. Das ist es! Dazu müssen wir unseren existierenden Code nur etwas modifizieren.

.clearfix:after {
    content: "."; 
    display: block; 
    height: 0; 
    clear: both; 
    visibility: hidden;
}

.clearfix {display: inline-block;}

/* Hides from IE-mac \*/
* html .clearfix {height: 1%;}
.clearfix {display: block;}
/* End hide from IE-mac */

Das .clearfix {display: inline-block;} wird von allen Browsern erkannt und löst für den IE/Mac das Problem. Dann wird innerhalb des vor IE/Mac verborgenen Regelsatzes display wieder auf block gesetzt. Man fügt den obigen Code einfach seinem CSS hinzu und benutzt .clearfix in jeder Box, die ein veränderbares Float enthält. Ist das nicht cool? Man achte nur wie vorher schon erwähnt auf vorangehende externe Floats, für die das IE Float Model ausgelöst werden könnte.

Eine wichtige Warnung!

Die W3C-Spezifikation für Floats fordert, daß ein Element mit der clear Eigenschaft unterhalb aller vorhergehenden Floats angezeigt wird. Es gibt keine Ausnahmen für diese Forderung! [Zweifel an dieser Aussage weisen auf den "Block formatting context", möge sich jeder Interessierte selbst ein Bild machen.] "Vorhergehend" meint in diesem Fall jedes Float, das vorher im Quelltext erscheint.

Bis November 2004 hat Firefox fälschlich nur Floats gecleart, die vertikal über dem clear Element angezeigt wurden, und nicht alle vorhergehenden Floats. Das bedeutete, daß man in diesen früheren Gecko-Browsern eine gefloatete Spalte an einer Seite des Viewports platzieren konnte, und im Innern einer weiteren Spalte (möglicherweise ebenfalls gefloatet) einen kleineren Innenfloat clearen konnte, ohne daß das clear Element unter die vorherige Float-Spalte gelangen konnte. Da nur Gecko dieses Problem hatte, war es offensichtlich, daß jedesmal irgendetwas falsch war, wenn dies bei einer Seite passierte. Normalerweise gehört Gecko zu den guten Browsern, aber in diesem einen Fall war er der Übeltäter. Merke: nicht immer ist IE der "Böse"!

Wie dem auch sei, die hier vorgestellte einfache clearing Methode hat die Angelegenheit ziemlich durcheinandergebracht, da der Explorer nun tatsächlich überhaupt nicht gecleart wird, während die Gecko-Browser jetzt so korrigiert wurden, daß sie alle vorhergehenden Floats clearen.

…oh nein! Es ist vorauszusehen, was jetzt in unserer hypothetischen Float-Seite passieren wird! Der IE, der keine wirklichen clearing Elemente kennt, wird großartig aussehen. Unterdessen wird in neueren Gecko-Browsern und Opera 7 das durch CSS generierte clearing Element in der ersten mit .clearfix versehenen Spalte die Länge dieses Elements weeeeit nach unten ziehen, bis der unsichtbare clearer vertikal unter den unteren Rand der vorhergehenden Floatspalte (vorausgesetzt, es gibt einen unteren Rand!) gelangen kann. Das kann einen enormen leeren Raum innerhalb dieser einst kleinen easy-geclearten Box "erzeugen", abhängig von der tatsächlichen Höhe der benachbarten Float-Spalte.

Natürlich hat Opera 7 - genau wie es auch der IE tut (abgesehen von Bugs) - die Spezifikationen für clear immer korrekt implementiert, und auch die Mac Browser sind hier nicht betroffen. Falls jetzt Verwunderung aufkommen sollte wie man diesen Fehler bereinigt, nun, das geht nicht. Gecko und Opera führen nun beide das Float-clearing korrekt aus, und der IE versagt nur wegen des gefakten "clearings", das wir ihm aufzwingen.

Vermeidung des Fremd-Clearings

Wenn man das oben erwähnte Problem hat, gibt es dennoch einen Weg zur Lösung. Man macht aus dem Container (dem der clearer innewohnt) einen floatenden Container. Wenn ein clearer innerhalb eines floatenden Containers liegt, wird er nur die ihm innerhalb dieses Containers vorangehenden Floats clearen. Das clearing Element wirkt nicht auf andere Floats außerhalb eines mittels Float platzierten Containers. Ebenso hat der clearer keine Auswirkung auf sein Elternelement, außer daß dieser alle enthaltenen Floats umschließt.

Okay, dies erfordert also strukturelle Änderungen, aber weniger, als man denkt. Wenn alle Hauptelemente in einem Spalten-Layout Floats sind, treten eigentlich die schlimmsten IE Float-Bugs nicht auf. Insofern kann kann die Anwendung einer "Nur Float Methode" auf das Spaltendesign tatsächlich einfacher zu bewerkstelligen sein, jedenfalls für ein Layout mit festen Breiten.

Mehr über IE/Mac und Floats

Nach Alex Robinson kann inline-block auf Blockelemente innerhalb von Floats angewendet werden, um den IE/Mac davon abzuhalten, Floats mit nicht definierter Breite auf volle Breite auszudehnen. Üblicherweise mußten Floats bisher eine definierte Breite haben, doch die neuen Spezifikationen erlauben Floats ohne Breitenangabe, die sich ihrem tatsächlichen Inhalt anpassen (shrinkwrapped). Als einziger der modernen Browser verbreitert der IE/Mac ein Float auf 100%, wenn das Float ein Blockelement enthält. Nun gut, man gibt nur für den IE/Mac dem eingebetteten Element ein "inline-block" mit der oben beschriebenen Versteckmethode und das float verhält sich auch in diesem Browser wie gewünscht. Doppeltes Juchuu! Man darf nur keine weiteren Blockelemente einbetten, da sie den Float wieder erweitern würden, ebenfalls sollte man das nicht mit rechten Floats probieren, wie Philippe Wittenbergh uns warnt. Danke für die Mac Tips, Philippe!

Danke an die, die sich die Arbeit gemacht haben

Dank an Tony Aslett, der uns den Weg zeigte. Seine Seite csscreator.com ist ein CSS "Killer"-Forum, wo Newbies und Gurus herumhängen und CSS-Wissen austauschen. Tonys ursprüngliche Demo-Seite für diese Methode ist hier zu finden, der relevante Forenthread ist hier [beide Links sind mittlerweile verwaist].

Kudos auch an Doug für den Hinweis auf das "Punkt-Problem" im Firefox, sowie an Mark Hadley für das Aufzeigen, wie "inline-table" auch dem IE/Mac mit einer bewährten CSS-Eigenschaft zum gewünschten Verhalten verhilft. Wieder einmal erreicht die CSS Community das Ziel zu unser aller Wohl! :-)

Holly 'n John   Contact us ©positioniseverything
Last updated: January 14, 2005
Created May 14, 2004