2011-03-25 12:41:04

Co się dzieje z tymi marginesami?

Collapsing margins jest zjawiskiem zapadania się (można też spotkać określenie „załamywania”) marginesów pionowych elementów sąsiadujących lub zagnieżdżonych. Zaprezentuję to na przykładzie.

<div id="kontener">
	<p>Hello</p>
</div>

Tworzę blok div o identyfikatorze kontener, a w nim umieszczam akapit. Chcę by akapit miał zielone tło i był odsunięty od krawędzi bloku div o 20 pikseli. Natomiast blok div ma mieć tło zielone. Tworzę więc następujące style.

#kontener
{
	background-color: #ffff00;
}
 
#kontener p
{
	margin: 20px; background-color: #00ff00;
}

To, co otrzymuję nie do końca spełnia moje oczekiwania.

Hello

O ile poziome marginesy zachowały się zgodnie z oczekiwaniami, to pionowe przeszły z akapitu do bloku div.

Problem dla konkretnego marginesu nie wystąpi, jeżeli przed lub po akapicie umieszczę jakąś zawartość.

Definicja stylu pozostaje bez zmian

<div id="kontener">
	Napis przed akapitem
	<p>Hello</p>
</div>

lub

<div id="kontener">
	<p>Hello</p>
	Napis po akapicie
</div>

Da mi odpowiednio

Napis przed akapitem

Hello

lub

Hello

Napis po akapicie

Margines pojawił się automatycznie od strony, z której umieściłem napis. Gdybym umieścił go po obu stronach, marginesy pojawiłyby się powyżej i poniżej akapitu. Co mam jednak robić jeżeli nie chcę umieszczać żadnej zawartości? W takiej sytuacji należy po prostu zmienić definicję styli.

<div id="kontener">
	<p>Hello</p>
</div>

Kod html pozostaje niezmieniony.

#kontener
{
	padding: 20px 0;
	background-color: #ffff00;
}
 
#kontener p
{
	margin: 20px; background-color: #00ff00;
}

Do definicji styli elementu #kontener dodaję 20 pikseli dopełnienia górnego i dolnego. Daje to następujący efekt.

Hello

Tym razem odstępy są zbyt duże. Margines akapitu został oddzielony właściwością padding elementu div i tym samym został przez przeglądarkę uwzględniony. To co widzimy na stronie to suma marginesu akapitu i dopełnienia elementu div. Aby poprawić ostateczny efekt należy pozbyć się pionowych marginesów akapitu.

#kontener
{
	padding: 20px 0;
	background-color: #ffff00;
}
 
#kontener p
{
	margin: 0 20px; background-color: #00ff00;
}

Wstawiam zero jako pierwszą wartość właściwości padding akapitu, czyli pionowe marginesy zostają wyzerowane przy niezmienionym stanie marginesów poziomych. Tym razem efekt jest następujący.

Hello

Co jednak, gdy będę chciał umieścić wewnątrz bloku div kilka akapitów tak, by pomiędzy nimi uzyskać 20 pikseli przerwy?

<div id="kontener">
	<p>Hello</p>
	<p>Hello</p>
	<p>Hello</p>
</div>

Hello

Hello

Hello

Dodam dla każdego akapitu marginesy pionowe: górny i dolny o wartości 10 pikseli. To powinno nam dać w sumie 20 pikseli przerwy. Aby odległość pomiędzy pierwszym akapitem, a górną krawędzią elementu div oraz pomiędzy ostatnim akapitem i dolną krawędzią elementu div nie została zwiększona do 30 pikseli. Zmniejszę wartość pionowego dopełnienia do 10 pikseli.

#kontener
{
	padding: 10px 0;
	background-color: #ffff00;
}
 
#kontener p
{
	margin: 10px 20px; background-color: #00ff00;
}

Hello

Hello

Hello

Ponownie efekt nie jest zgodny z oczekiwanym. Tym razem marginesy pomiędzy akapitami zostały zredukowane do jednego marginesu. Gdyby marginesy akapitów górny i dolny nie były sobie równe. Odległość pomiędzy akapitami zostałaby zredukowana do większego z marginesów.

Aby marginesy były takie, jakie być powinny, wyzeruję jeden z marginesów akapitów, a drugi ustawię na 20 pikseli. Nie ma większego znaczenia, czy wyzeruję górny, a zwiększę dolny, czy odwrotnie. Będę tylko musiał pamiętać o zmianie odpowiedniego dopełnienia bloku div.

#kontener
{
	padding: 1px 0 20px;
	background-color: #ffff00;
}
 
#kontener p
{
	margin: 20px 20px 0; background-color: #00ff00;
}

Każdy akapit ma margines górny równy 20 pikseli, marginesy poziome równe 20 pikseli i margines dolny równy 0. Natomiast dopełnienia elementu div zmieniły się odwrotnie. To dopełnienie górne zostało zredukowane wprawdzie do 1 piksela, a nie do 0, ale wyzerowanie tej wartości doprowadziłoby do zapadnięcia się marginesu górnego pierwszego akapitu w marginesie górnym bloku div, co obrazuje pierwszy przykład tej lekcji. Jeżeli nie potrzebujemy dokładności co do piksela, to rozwiązanie jest zupełnie zadowalające. Zresztą wystarczy spojrzeć poniżej.

Hello

Hello

Hello

Jeżeli jednak ta dokładność jest potrzebna, należy dodać jeszcze jedną właściwość w definicji stylu.

#kontener
{
	padding: 1px 0 20px;
	background-color: #ffff00;
}
 
#kontener p
{
	margin: 20px 20px 0; background-color: #00ff00;
}
 
#kontener p:first-child
{
	margin-top: 19px;
}

Selektor #kontener p:first-child wskazuje tylko na pierwszy akapit zawarty w elemencie #kontener i tylko dla niego zmniejsza górny margines do 19 pikseli, co łącznie z górnym dopełnieniem daje wartość 20. Niestety to rozwiązanie nie działa w przeglądarce IE nawet w wersji 8. Problem ten można ominąć nadając pierwszemu akapitowi dowolny identyfikator np: id=”pierwszy”. Wówczas selektor powinien wyglądać: #kontener p#pierwszy. Jeżeli takich fragmentów kodu na stronie mamy kilka, zamiast identyfikatora używamy klasy.

Hello

Hello

Hello

Prezentowany przypadek jest dosyć prosty, w praktyce można natknąć się na bardzo różne układy elementów i różne też będą zaplanowane efekty. Z tego względu powyższych rozwiązań nie należy bezmyślnie kopiować. Mają one jedynie wskazać ogólny kierunek szukania rozwiązań.

Jeżeli ktoś z czytelników spotkał się w swojej pracy z szczególnie interesującym problemem związanym z collapsing margins, to proszę o przysłanie kodu z opisem oczekiwanego rezultatu na adres trener@serwan.pl. Rozwiązanie 2-3 ciekawszych przykładów zaprezentuję w jednej z najbliższych lekcji. Zachęcam również do pozostawiania komentarzy poniżej.

Tagi: , ,

Jedna odpowiedź do “Co się dzieje z tymi marginesami?”

  1. Adam pisze:

    Miałem dokładnie ten sam problem ostatnio, dzięki :) )

Dodaj odpowiedź