Przy obecnej popularności webdesignu (a raczej bycia trendy i walidacji, o czym pisałem w zeszłym miesiącu), co drugi użytkownik sieci cytuje z pamięci regułki CSS, sypie kodem (X)HTML, chwali się beztabelkowymi osiągnięciami. Często te beztabelkowce zajmują pięć razy więcej miejsca (ale przecież bandwidth is cheap) i w środku korzystają z display: table;, ale nie o tym chciałem pisać. Zajmijmy się problemami, w rozwiązaniu których standardy niewiele pomagają.

Jedną z rzeczy, którą można bardzo łatwo zaimplementować za pomocą semantycznego HTML + CSS jest układ kolumnowy. Używa się do tego dwóch elementów <div/>, z czego jeden jest floatowany do krawędzi.

<div id="navbar">
	<p>To jest menu</p>
</div>
<div id="content">
	<p>To jest treść strony</p>
</div>
#navbar
{ 
	margin: 0 10px;
	background-color: #69f;
	float: left;
	width: 180px;
	height: 400px;
	border: 1px solid #ccc;
}
#content 
{ 
	width: 475px;
	border: 1px solid #ccc;
	background-color: #fff;
}

Problemy zaczynają się pod IE, który raz, że nie radzi sobie z precyzyjnym pozycjonowaniem floatów (jeśli floatowany element jest dokładnie szerokości dostępnego miejsca, to następuje złamanie wiersza, wymagany jest dwupikselowy zapas), a dwa, z nieznanych nikomu przyczyn magicznie podwaja marginesy wszystkich pływających elementów, jeśli tylko są typu block.

O ile jedynym rozwiązaniem na precyzyjne umiejscowienie dwóch kolumn jest zastąpienie obu bloków dwukolumnową tabelką, o tyle drugi problem rozwiązuje się trywialnie. Tyle, że nikt przy zdrowych zmysłach by na takie rozwiązanie nie wpadł. Należy mianowicie wymusić na przeglądarce traktowanie elementów floatowanych jako elementy typu inline. Wyjście takie wydaje się mocno abstrakcyjne i pozbawione sensu, ale działa, wobec tego ograniczymy jego skutki do jedynej słusznej przeglądarki, która obejść takich wymaga.

#navbar
{ 
	margin: 0 10px 0 0;
	background-color: #69f;
	float: left;
	width: 180px;
	height: 400px;
	border: 1px solid #ccc;
}
* html #navbar
{
	display: inline;
}

Trik polega na tym, że w IE nie działa właściwie nic, a przede wszystkim nie działają tam selektory CSS, z selektorem gwiazdki na czele. Powyższa konstrukcja mówi tyle, że display: inline; powinno odnosić się do wszystkich elementów o id równym navbar, zawierających się w elemencie <html/>, który ma dowolnego rodzica. Standard HTML wyraźnie precyzuje, że element główny, <html/> nie może mieć żadnego rodzica w ramach jednego dokumentu (nie dotyczy to drzewa DOM stron opartych na ramkach, ale tam CSS przypisywany jest do każdego węzła głównego i nie jest dziedziczony przez subdokumenty). IE uważa, że jest inaczej, co pozwala (przynajmniej do wersji 6.0) łatwo ukrywać workaroundy przed innymi przeglądarkami.

Oczywiście, bardziej eleganckim rozwiązaniem byłoby dodanie marginesu (równego szerokości lewej kolumny + pożądanemu odstępowi) do prawej kolumny:

#navbar
{ 
	background-color: #69f;
	float: left;
	width: 180px;
	height: 400px;
	border: 1px solid #ccc;
}
#content 
{ 
	margin: 0 0 0 190px;
	width: 475px;
	border: 1px solid #ccc;
	background-color: #fff;
}

Nie rozwiązuje to jednak problemu układów bardziej skomplikowanych (gdzie stosujemy więcej niż dwie kolumny z floatem).

Drugi z częstych problemów, to zmuszenie elementów pływających do rozciągania rodzica. Weźmy pod uwagę prosty układ:

<div id="parent">
	<div id="child">
		<p>Lorem ipsum dolor sit amet
		consectetuer adipiscing elit.</p>
	</div>
	<p>Lorem ipsum, baby!</p>
</div>
#parent
{
	background: #fff;
	border: 1px solid #ccc;
	color: #000;
	padding: 5px;
}
#child
{
	background: #eee;
	border: 1px solid #ccc;
	color: #000;
	float: right;
	width: 100px;
}

Ze względu na stosunkowo długi tekst w pływającym boksie (w porównaniu do krótkiego tekstu głównego), istnieje ryzyko, że boks dziecka będzie dłuższy od boksa rodzica, co (zgodnie ze standardem) spowoduje jego wystawanie poza obiekt rodzica (nie zostanie od przedłużony). Nie jest to na ogół działanie, jakiego oczekujemy, pojawiło się więc kilka rozwiązań tej niedogodności.

Najpopularniejsze polega na wstawieniu, tuż przed tagiem zamykającym rodzica, następującego zapisu:

<br style="clear: both;">

Metoda ta ma jednak dwie wady: niepotrzebnie zaśmieca kod strony (co jest dla wielu do pominięcia) i powoduje pojawienie się zbędnego znaku złamania wiersza (co w zależności od pogody i populacji muflona, jest przez IE ignorowanie bądź nie).

Najczystsza metoda nie wymaga ingerencji w kod HTML i sprowadza się do dodania w arkuszu CSS (dla elementu rodzica) jednej linijki:

overflow: auto;

Przeglądarka od tego momentu zaczyna się interesować wystającymi elementami i elegancko przedłuży nam obiekt rodzica do wymaganego rozmiaru. Należy jednak uważać, bo gdy rodzic ma zadeklarowaną stałą wysokość, to w jego boksie pojawią się paski przewijania (uzyskamy efekt taki, jak przy elemencie <iframe/>.

Kolejny problem to wymuszenie minimalnej wysokości elementu. Najprościej byłoby napisać:

#element
{
	min-height: 300px;
}

Jest jednak przeglądarka, która w dziedzinie wspierania standardów nigdy nas nie zawiedzie. IE skrupulatnie ignoruje wszelkie zapisy tego typu. Co więcej, nieprawidłowo implementuje też atrybut height, który w IE zachowuje się właśnie jak min-height. Z pomocą przychodzi nam wspomniany wcześniej hack:

#element
{
	min-height: 300px;
}
* html #element
{
	height: 300px;
}

I kolejny problem: model boksa w IE prawidłowo został zaimplementowany dopiero w IE 6.0 i to tylko w trybie strict (w przeciwieństwie do domyślnego quirks mode). Powoduje to, że w przeglądarkach z Redmont padding nie wpływa na finalny rozmiar boksa. Innymi słowy, jeśli nasz obiekt ma szerokość zadeklarowaną na 100px i 20px paddingu z obu stron, to w IE zajmie dokładnie 100px, a na treść pozostanie 60px (po odjęciu 2x 20px), podczas gdy we wszystkich pozostałych przeglądarkach element zajmie 140px, rezerwując na treść całe (zadeklarowane w CSS) 100px.

Jeśli nie jest wymagana zgodność ze starszymi przeglądarkami (np. IE 5.5), to problem dla ciebie nie istnieje. Wystarczy zadeklarować prawidłowy DOCTYPE i wymusić przejście przeglądarki w strict mode. W biznesie webdesignowym rzadko można sobie pozwolić na tego typu uproszczenia, bo ważny jest każdy klient serwisu, niezależnie od tego, jak starej przeglądarki używa. Jedynym sensownym rozwiązaniem pozostaje symulowanie paddingu za pomocą zagnieżdżonych elementów i marginesów.

<div id="outer">
	<div id="inner">
		<p>Treść.</p>
	</div>
</div>
#outer
{
	/* padding: 5px */
}
#inner
{
	height: 100%;
	margin: 5px;
}

W zależności od popularności tego tekstu, postaram się opisać więcej błędów i problemów, póki co - czekam na komentarze.