torsdag 31 maj 2012

Varför fungerar inte alltid margin-top i CSS?

Har man byggt webbsidor i HTML och CSS ett tag lär man förr eller senare stöta på ett märkligt fenomen med marginaler (margin). Det gäller framför allt margin-top och margin-bottom.

Låt oss titta på exemplet nedan.


Vi har två stycken DIV-taggar, där den ena ligger i den andra. Den yttre rosa boxen har en top marginal på 50 pixlar och är 500 x 200 pixlar stor. På den inre gula boxen har vi en 50 pixlar stor marginal runt om och en 10 pixlar stor padding. Inga konstigheter.

Låt oss kolla på lite källkod:

CSS: 

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:block;
}

HTML:

<div id="outer">
    <div id="inner">
        Hello world!
    </div>
</div>


Men som ni kanske gissar så händer något oväntat. Låt oss kolla hur det ser ut.


Marginalen på den inre gula boxen försvinner och istället limmas den i toppen. Vilket är helt ologiskt kan man tycka. Men det hela handlar om hur CSS är uppbyggt och just detta fenomen kallas "Collapsing margins", eller kollapsande marginaler.

Så här säger W3 om denna standard:

8.3.1 Collapsing margins
In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.
Adjoining vertical margins collapse [...]

Mer läsning på:
http://www.w3.org/TR/CSS2/box.html#collapsing-margins

Detta betyder alltså att två angränsande boxars yttre vertikala marginaler går samman/kollapsar för att forma en gemensam marginal. Horisontala marginaler kollapsar dock aldrig.

Varför gör man såhär då?
Det hela handlar lite om hur man tänker på margin och padding. Vad är det egentligen? Margin, eller som jag här i texten beskriver det "yttre marginaler", bör inte tolkas som att flytta ett objekt 50 pixlar hit eller dit snarare att det ska minst finnas 50 pixlar tomt utrymme ovan de två objekten.

Det fungerar faktiskt på samma sätt i exempelvis ordbehandlaren Word. En rubrik med en marginal på 12 pixlar följt av en paragraf med 6 pixlar marginal ger inte ett mellanrum på 18 utan istället 12 pixlar. Den mindre marginalen kollapsar in i den större för att ge en minsta önskad marginal mellan de två. Följande paragrafer hade alla haft 6 pixlars marginal mellan varandra.

Hade det inte fungerat på detta sättet hade det blivit väldigt svårt att formatera text både i Word och i HTML med CSS.

Padding å andra sidan skapar alltid ett mellanrum. Padding betyder rakt översatt ungefär utfyllnad.

Lägger vi boxarna efter varandra istället för i varandra ser vi det tydligare:

CSS:

#box1 {
    width:500px;
    height:200px; 
    background:#FFCCCC;
    margin:50px;
    padding:20px;
}
#box2 {
    width:500px;
    height:200px; 
    background:#FFCC33;
    margin:50px;
    padding:20px;
}

HTML:

<div id="box1">
Hello
</div>
<div id="box2">
world!
</div>



Som vi ser får vi inte 100 pixlars mellanrum utan bara 50. Detta trotts att vi har 50 pixlars marginal runt om båda boxarna, alltså både i toppen och foten samt höger och vänster. Men footen i den övre och toppen i den undra boxens marginaler kollapsar för att ge den gemensamma marginalen på 50 pixlar, precis som vi önskade.

Så marginaler kollapsar. Detta är i alla fall sant så länge det inte finns andra regler som skapar en barriär mellan de boxarna eller förändrar boxmodellen för någon av dem. Exempel på detta skulle kunna vara att ändra den inre boxen till floating, eller gör den till ett inline-block eller den yttre boxen till att ha hidden overflow eller ha en padding.

Alla förändringar ger fortfarande inte önskvärt resultat, men löser i alla fall problemet med att marginalen kollapsar.

Bäst resultat får vi om vi sätter overflow:hidden; på den yttre boxen.

CSS:

#outer {
    width:500px;
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
}


Alternativt kan vi lägga på en 1 pixels padding på den yttre boxen. Padding gör dock boxen större så vill vi ha exakt 200 pixlar hög box får vi ändra höjden till 199 pixlar.


#outer {
    width:500px;
    height:199px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
padding:1px 0 0 0;
}


Det kan fortfarande verka ologiskt att det fungerar som det gör, men detta ger i alla fall en liten förklaring till varför och hur man kan lösa det.

Inga kommentarer:

Skicka en kommentar