Artykuł ten jest tłumaczeniem kolejnego świetnego artykułu CSS Floats 101 autorstwa Noah Stokes, zamieszczonego na A List Apart. Noah Stokes wyraził zgodę na przetłumaczenie i opublikowanie jego artykułu na moim blogu, za co serdecznie mu dziękuję. Zaznaczam, że nie jestem autorem poniższego tekstu, a jedynie autorem tłumaczenia.

CSS Floats 101

Float to bardzo wartościowa i potężna właściwość, przydatna każdemu web designer/developer -owi wykorzystującemu w swojej pracy HTML i CSS. Niestety, może być ona także przyczyną frustracji i nieporozumień, jeśli dobrze nie zrozumiesz zasad jej działania. Dodatkowo, w przeszłości miała ona związek z paroma uciążliwymi błędami przeglądarek, więc to całkiem normalne, że używanie jej w zestawie reguł CSS może denerwować. Spróbujmy jednak ukoić skołatane nerwy i złagodzić frustrację. Pokażę wam dokładnie w jaki sposób właściwość float wpływa na zachowanie elementów i jak nieprawdopodobnie przydatna może być, kiedy już nad nią zapanujesz.

W świecie druku z właściwością float stykamy się za każdym razem, kiedy sięgamy po czasopismo z tekstem elegancko opływającym zdjęcia i obrazki z lewej i prawej strony. W świecie HTML/CSS -a, zupełnie jak w czasopismach, tekst opłynie wokół zdjęcia, jeśli przypiszemy mu właściwość float. Zdjęcia są tylko jednym z wielu przykładów użycia tej właściwości – z jej pomocą możemy np. zbudować często spotykany układ dwukolumnowy. W zasadzie tę właściwość można zastosować do dowolnego elementu HTML, a posiadłszy i zrozumiawszy podstawy jej stosowania oraz podstawy pozycjonowania elementów, będziesz w stanie bez problemu zbudować dowolny layout.

Definicja

Zacznijmy od definicji właściwości float:

Pole pływające to pole dosunięte do lewej lub prawej krawędzi linii. Najciekawszą cechą pól pływających jest to, że obok nich może znajdować się jakaś treść (chyba że zostanie to zabronione za pomocą własności ‘clear’). Pola spływające do lewej krawędzi pozwalają na występowanie treści po prawej stronie, a pola spływające do prawej — po lewej stronie.

Właściwości float możemy przypisać cztery wartości: left, right, inherit i none. Każda z nich brzmi dość wymownie. Na przykład, jeśli elementowi przypiszemy float:left, to przesunie się on do lewej krawędzi elementu-rodzica. Analogicznie, jeśli elementowi przypiszemy float:right, przesunie się on do prawej krawędzi elementu-rodzica. Wartość inherit oznacza, że element odziedziczy wartość float po elemencie nadrzędnym, natomiast wartość none jest wartością domyślną każdego elementu i jest równoznaczna z brakiem własciwości float.

Oto prosty przykład nawiązujący do fragmentu o czasopismach powyżej – przykład A oraz odpowiednie właściwości:

img {
  float: right;
  margin: 10px;
}

Zachowanie elementów pływających

Niby nic, a jednak coś, prawda? Ktoś powie – dziecinada. W porządku, zanim jednak dojdziemy do miejsca, w którym zacznie sprawy naprawdę się skomplikują, sprawdźmy, co tak naprawdę się wydarzyło. W sieci, nasz kod HTML jest wyświetlany według pewnych reguł obowiązujących w ramach tzw. układu normalnego. W układzie normalnym, elementy blokowe (div, p, h1, itd.) ułożą się w stosie – jeden pod drugim, począwszy od górnej krawędzi obszaru widoku (viewport). Elementy pływające (z ustawioną właściwością float – przyp. aut.) zostaną wyjęte spod reguł panujących w układzie normalnym i przesunięte lewej lub prawej krawędzi elementu-rodzica, w zależności od ustawionej wartości właściwości float. Innymi słowy, zamiast układać się jeden pod drugim, będą układać się jeden obok drugiego, jeśli pozwoli na to szerokość elementu-rodzica. I o tym należy zawsze pamiętać budując serwisy internetowe.

Przyjrzyjmy się paru innym przykładom. W przykładzie B umieszczono trzy elementy blokowe bez ustawionej własciwości float:

.block {
  width: 200px;
  height: 200px;
}

Zauważyłeś, jak elementy układają się jeden pod drugim? Tak właśnie zachowują się elementy w układzie normalnym. A teraz ten sam przykład, ale tym razem wszystkim elementom ustawimy właściwość float – oto przykład C:

.block {
  float: left;
  width: 200px;
  height: 200px;
}

Tym razem elementy ułożyły się jeden obok drugiego. Świetnie, udało nam się to rozpracować. Ale co ze wspomnianym wcześniej warunkiem „jeśli pozwoli na to szerokość elementu-rodzica”? Myślałem, że nie zapytasz. Weźmy nasz ostatni przykład, zwiększając jednak liczbę elementów do pięciu. W tym wypadku elementem-rodzicem jest element body dokumentu. Zauważ, że w zależności od szerokości okna przeglądarki (a w konsekwencji szerokości elementu-rodzica, czyli body), elementy blokowe przenoszą się niżej, do kolejnego rzędu, ponieważ w pierwszym rzędzie brakuje miejsca na to, żeby wyświetlić je wszystkie obok siebie. W miarę zwiększania okna przeglądarki zauważysz, że przemieszczają się ponownie. Przekonaj się sam na przykładzie D.

Clear

Właściwość float posiada przyrodnią siostrę, właściwość clear. Te dwie właściwości uzupełniają się w stopniu, który uczyni z Ciebie szczęśliwego kodera. Jak wspomniałem wcześniej, element pływający zostanie wyjęty spod reguł panujących w układzie normalnym. Oznacza to, że kolejny, następujący po nim element, będzie zachowywać się inaczej, niż mógłbyś się spodziewać. To jest ten moment, w którym, jak sądzę, pojawią się pewne problemy. Rzućmy okiem na przykład E. W tym przykładzie, przypisałem właściwość float dwóm elementom (różowemu i niebieskiemu), zaraz za nimi umieściłem dwa kolejne elementy bez właściwości float (zielony i pomarańczowy). Poniżej kod HTML i CSS:

<div class="block pink float"></div>
<div class="block blue float"></div>
<div class="block green"></div>
<div class="block orange"></div>
.block {
  width: 200px;
  height: 200px;
}
.float { float: left; }
.pink { background: #ee3e64; }
.blue { background: #44accf; }
.green { background: #b7d84b; }
.orange { background: #E2A741; }

I jak Ci się podoba ten zielony element? Zaraz, moment… ale gdzie on jest? Jest, tyle że schowany pod elementem różowym. Elementy różowy i niebieski z ustawioną właściwością float zachowują się zgodnie z oczekiwaniami, układając się jeden obok drugiego. Ponieważ jednak są przez to wyjęte spod reguł układu normalnego, są także ignorowane przez elementy zielony i pomarańczowy.Właśnie dlatego element zielony schował się pod tym różowym. Jak więc sprawić, żeby element zielony znów był widoczny? Używając właściwości clear.

Właściwośc clear przybiera jedną z pięciu wartości: left, right, both, inherit i none. Przypisanie wartości left sprawi, że górna krawędź elementu zostanie osadzona poniżej pierwszego napotkanego elementu z ustawioną właściwością float:left. Analogicznie – element z przypisaną wartością right zostanie osadzony poniżej pierwszego napotkanego elementu z ustawioną wartością float:right. Wartość both osadzi element tak, że jego górna krawędź znajdzie się poniżej pierwszego napotkanego elementu z ustawioną właściwością float:left lub float:right. Wartość inherit oznacza dziedziczenie wartości właściwości clear po elemencie-rodzicu, natomiast domyślna wartość none oznacza dokładnie to, co sugeruje nazwa. Wiedząc to wszystko, zerknijmy na przykład E2. Tym razem użyliśmy właściwości clear na elemencie zielonym. Nieznacznie zmodyfikowany kod prezentuje się następująco:

<div class="block pink float"></div>
<div class="block blue float"></div>
<div class="block green clear"></div>
<div class="block orange"></div>
.block {
  width: 200px;
  height: 200px;
}

.float { float: left; }
.clear { clear: left; }
.pink { background: #ee3e64; }
.blue { background: #44accf; }
.green { background: #b7d84b; }
.orange { background: #E2A741; }

Nadając zielonemu elementowi właściwość clear, daliśmy mu do zrozumienia, że ma zachowywać się tak, jakby element różowy był dalej częścią układu normalnego, mimo, że nie jest, i ułożył się pod nim. To jest niezwykle ważna właściwość, która pozwala elementom bez float’ów powrócić na właściwe miejsce, tak jak byśmy tego oczekiwali. Reasumując – poznanie i zrozumienie właściwości float i clear otwiera przed nami kolejne drzwi do lepszego kodowania.

Pływanie w layoutach

Spróbujmy zaprojektować jakiś layout. To właśnie tu właściwość float bardzo się przydaje. Możemy zbudować typowy dwukolumnowy układ na mnóstwo sposobów – w większości z nich wykorzystamy kilka pływających elementów. Spójrzmy na prosty przykład: dwu kolumnowy układ strony z kontentem po lewej stronie, nawigacją po prawej oraz nagłówkiem i stopką. Na potrzeby tego artykułu przyjrzymy się wyłącznie części kodu związanej z właściwością float. Oto przykład F:

#container {
  width: 960px;
  margin: 0 auto;
}

#content {
  float: left;
  width: 660px;
  background: #fff;
}

#navigation {
  float: right;
  width: 300px;
  background: #eee;
}

#footer {
  clear: both;
  background: #aaa;
  padding: 10px;
}

Ok, zobaczmy co się tutaj właściwie dzieje. Nasz kontener główny został, skądinąd słusznie, nazwany #container. Utrzymuje on nasze pływające elementy we właściwym miejscu. Gdyby go nie było, elementy ustawiłyby się przy krawędziach obszaru widoku (czyli okna przeglądarki w tym wypadku). Kolejne elementy to #content i #navigation. Te elementy mają ustawioną właściwość float. Aby uzyskać układ dwukolumnowy ustawiamy #content po lewej stronie, a #navigation po prawej. Obu elementom określiłem szerokość tak, żeby pasowały do szerokości elementu-rodzica. Na końcu ustawiamy właściwość clear elementowi #footer. Jak ustaliliśmy wcześniej, właściwość ta przywróci opływające elementy do układu normalnego. W naszym przykładzie element #footer ma przypisaną wartość both, tak więc zostanie osadzony poniżej zarówno elementu #content jak i #navigation.

Co stałoby się, gdybyśmy nie przypisali właściwości clear to elementu #footer? Zerknijmy na przykład G.

Stopka #footer przesunęła się pod element #navigation. Stało się tak, ponieważ pod elementem #navigation jest wolne miejsca, w które stopka może się wpasować i biorąc pod uwagę reguły panujące w normalnym układzie, jest to zachowanie jak najbardziej prawidłowe. Nie jest to jednak to zachowanie, o które nam chodzi, prawda? Widać za to wyraźnie zależności pomiędzy właściwościami float i clear oraz sposób, w jaki na siebie wzajemnie oddziałują.

Jeśli cierpisz na manie natręctw, jak ja, zauważysz z pewnością, że w przykładzie F wysokości elementów #content i #navigation nie są równe. Można je wyrównać na kilka różnych sposobów, jednak nie to jest tematem tego artykułu. Jeśli jesteś zainteresowany jak to zrobić, szczególnie polecam artykuł Faux Columns Dana Cederholma wyjaśniający, jak sprawić, by wysokość obu takich elementów wydawała się być identyczna niezależnie od zawartości.

Najpierw float

Jak na razie przyjrzeliśmy się paru prostym i przystępnym przykładom, które nie powinny sprawić problemów. Istnieją jednak pułapki, na które należy zwracać szczególną uwagę używając właściwości float. Co ciekawe, czają się one nie w kodzie CSS, ale w samym HTMLu. Rezultat może być różny, w zależności od tego, gdzie umieścisz element pływający w kodzie HTML. Zerknij na przykład H.

Mamy tu niewielkie pole z pojedynczym, pływającym po prawej stronie zdjęciem i opływającym go tekstem. Oto nasz kod CSS:

#container {
  width: 280px;
  margin: 0 auto;
  padding: 10px;
  background: #aaa;
  border: 1px solid #999;
}

img {
  float: right;
}

Dość wąski element-rodzic #container utrzymuje element pływający w swoich granicach. Kod HTML wygląda następująco:

<div id="container">
  <img src="image.gif" />
  <p>This is some text contained within a
small-ish box. I'm using it as an example
of how placing your floated elements in different
orders in your HTML can affect your layouts. For
example, take a look at this great photo
placeholder that should be sitting on the right.</p>
</div>

Ten prosty zabieg daje nam pożądany rezultat, co jednak stanie się, kiedy w tym samym przykładzie wprowadzimy niewielkie zmiany w kodzie HTML? W przykładzie I przesunęliśmy element img poniżej paragrafu z tekstem:

<div id="container">
  <p>This is some text contained within a
small-ish box. I'm using it as an example
of how placing your floated elements in different
orders in your HTML can affect your layouts. For
example, take a look at this great photo
placeholder that should be sitting on the right.</p>
  <img src="image.gif" />
</div>

Rezultat zdecydowanie nie jest taki, jakbyśmy oczekiwali. Wprawdzie nasz obrazek w dalszym ciągu pływa po prawej stronie, ale nie w prawym górnym rogu, jak ochcieliśmy. Zamiast tego wyświetla się poniżej paragrafu z tekstem, co gorsze – wystaje poza dolną krawędź elementu-rodzica #container. O co chodzi? Po pierwsze – zasada, do której zawsze stosuję się w moich projektach – zasada float first (najpierw float – przyp. aut.). W kodzie HTML elementy pływające prawie zawsze umieszczam przed elementami niepływającymi, takimi jak np. paragraf z powyższego przykładu. Po drugie – powód, dla którego obrazek wystaje poza dolną krawędź elementu-rodzica #container ma związek z czymś, co określamy mianem scalania (collapsing). Zobaczmy czym jest scalanie i co możemy z nim zrobić.

Scalanie

O scalaniu mówimy wtedy, gdy element-rodzic zawierający dowolną ilość elementów pływających, nie otacza ich całkowicie, jak miałoby to miejsce w przypadku układu normalnego. W powyższym przykładzie I, element rodzic #container, ułożył się tak, jakby element img w ogóle nie istniał. To nie jest błąd przeglądarki, to prawidłowe i spodziewane zachowanie. Skoro elementy pływające są wyjęte spod reguł układu normalnego, element #container nie uwzględnia ich w swoich granicach i zachowuje się tak, jakby ich w ogóle nie było. Na marginesie, Eric Mayer napisał wspaniały artykuł pod tytułem Containing Floats, który dogłębnie omawia ten temat i jest cennym źródłem informacji. Dobra wiadomość jest taka, że ten problem można rozwiązać na mnóstwo sposobów. Jeśli myślisz, że ma to związek z właściwością clear, to jesteś bliski prawdy.

Jednym z najszerzej stosowanych rozwiązań jeśli chodzi o scalanie elementu rodzica jest umieszczenie nowego elementu z właściwością clear pod elementem pływającym. W efekcie element-rodzic otoczy również element pływający. Będzie prościej zobaczyć to na przykładzie. Spójrz na kod HTML w przykładzie J, który poza jednym dodanym elementem, nie różni się niczym od poprzedniego przykładu:

<div id="container">
  <p>This is some text contained within a
small-ish box. I'm using it as an example
of how placing your floated elements in different
orders in your HTML can affect your layouts. For
example, take a look at this great photo
placeholder that should be sitting on the right.</p>
  <img src="image.gif" />
  <div style="clear: right;"></div>
</div>

Umieszczając w kodzie element div z właściwością clear:right wymusiliśmy na elemencie #container zmianę wysokości i uwzględnienie w niej obrazka. To rozwiązanie oczywiście działa, jednak nie jest ono zbyt eleganckie, bo wymaga umieszczenia dodatkowego znacznika w kodzie. O wiele bardziej seksowne byłoby rozwiązanie tego problemu z poziomu CSSa. Istnieje kilka sposób, żeby to osiągnąć – przyjrzyjmy się paru z nich.

Rozważmy następujący przykład – element-rodzic zawiera trzy pływające obrazki. Nasz kod HTML będzie wyglądać następująco:

<div id="container">
  <img src="image.gif" />
  <img src="image.gif" />
  <img src="image.gif" />
</div>

a nasz kod CSS tak:

#container {
  width: 260px;
  margin: 0 auto;
  padding: 10px 0 10px 10px;
  background: #aaa;
  border: 1px solid #999;
}

img {
  float: left;
  margin: 0 5px 0 0;
}

Analizując ten przykład szybko zauważymy, że element-rodzic nie otacza pływających elementów. Raz jeszcze – to normalne zachowanie, wynikające z faktu, że elementy pływające są wyjęte spod reguł normalnego układu, więc element-rodzic #container zachowuje się tak, jakby ich w ogóle nie było. Spójrz na przykład K.

Spróbujmy teraz rozwiązać ten problem stosując wyłącznie reguły CSS, bez dodawania nowego znacznika HTML jak we wcześniejszym przykładzie. Istnieje taka technika, która umożliwia dowolnemu elementowi otoczyć umieszczone w nim elementy pływające. Wykorzystuje ona właściwość CSS zwaną overflow z przypisaną wartością hidden. Warto zaznaczyć, że właściwość overflow nie została stworzona z myślą o takim zastosowaniu, więc może powodować rożne problemy, np. ukrywać zawartość lub wyświetlać niechciane scrollbary. Możesz poczytać więcej na ten temat tutaj oraz tutaj. Wracając do naszego przykładu, przypisaliśmy overflow:hidden do elementu-rodzica #container:

#container {
  overflow: hidden;
  width: 260px;
  margin: 0 auto;
  padding: 10px 0 10px 10px;
  background: #aaa;
  border: 1px solid #999;
}

Rezultat można zaobserwować w przykładzie L. Całkiem nieźle, nie? Inna metoda, mniej ryzykowna, która skutkuje tym samym, wymaga użycia pseudo klasy :after. W naszym przykładzie kod będzie zatem wyglądać następująco:

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

Kod CSS pod elementem #container umieszcza nowy element z pewną zawartością (w tym wypadku będzie to kropka), oraz określa jego widoczność jako ukrytą, a wysokość ustawia na zero. Bardzo szczegółowy opis tej techniki znajdziesz w artykule Position is Everything.

Ostatnią metodę radzenia sobie z problemem scalania wyjaśnia Eric Mayer w artykule Containing Floats. Zgodnie ze specyfikacją CSS 2.1:

element pływający zwierający elementy pływające, rozciągnie się

Tak więc w tym wypadku, nadanie właściwości float elementowi #container spowoduje, że rozciągnie się on i otoczy zarówno paragraf z tekstem jak i obrazki, podobnie jak w przypadku poprzednich technik.

Ostatecznie wszystkie te techniki dają identyczny rezultat. Sprawiają, że element-rodzic otocza pływające elementy-dzieci. Wszystkie mają zarówno wady jak i zalety, Ty natomiast powinieneś zapoznać się z nimi i wybrać tę, która najbardziej Ci pasuje.

Co może przyprawić o ból głowy

Wierz lub nie, jest istnieją błędy przeglądarek, które wypłynął na wierzch, kiedy zaczniesz używać elementów pływających, takie jak np. double margin bug albo the 3px Text-Jog. Oba błędy wykraczają poza zakres omawiany w artykule. Na szczęście oba można również stosunkowo łatwo zniwelować, jeśli zamierzamy wspierać starsze przeglądarki.

Wnioski

Właściwość float z pewnością udoskonali Twoją technikę budowania layoutów czyniąc ją bardziej elastyczną. Dobre zrozumienie zasad jej działania i sposobu, w jaki oddziałuje na elementy, jest najlepszym sposobem na jej efektywne wykorzystanie.

———————————————————————–
Przy tłumaczeniu wykorzystano tłumaczenie specyfikacji CSS 2.1 autorstwa pana Łukasza Piwko.

Podobne wpisy: