Float i inline-block

W dzisiejszym artykule mała powtórka z przeszłości.
Sporo młodych webmasterów twierdzi, że nie ma sensu uczyć się technik związanych z floatami i display:inline-block, bo w dzisiejszych czasach są inne techniki.
Moje zdanie jest odmienne. Dobry webmaster nie musi używać tych technik. Ale musi je znać, bo pewnego dnia może na nie natrafić. I wtedy co powie? Wie pan – ja panu tego nie zrobię, bo ja umiem tylko nowe…

Wracając do tematu. Poniżej mała powtórka z tego z czym się je te rzeczy.

Float

Właściwość float sprawia, że dany element jest wyciągany na daną stronę (left, right). Reszta layoutu zaczyna go wtedy opływać.
Jeżeli kilka elementów obok siebie będzie miało float, wtedy ułożą się obok siebie.
Wykorzystywane jest to bardzo często do układania layoutów – np przy gridach. Kolejne kolumny -col dostają float i odpowiednią procentową szerokość. Całość upakowana jest w .row.

* {box-sizing:border-box;}

.row {}
.row::after { /* clearfix - patrz dalej */
    content: "";
    display: table;
    clear: both;
}
.row .col-1-3 {
	float: left;
	width: 33.3333%;
	padding-left: 15px;
	padding-right: 15px;
}

@media (max-width:600px) {
  	.row .col-1-3 {
    	width:100%;
	}
}

.element {
	/* dopiero tutaj stylujemy elementy w kolumnach - nie stylujemy samych kolumn */
}
<div class="row">
	<div class="col-1-3">
		<div class="element"></div>
	</div>
	<div class="col-1-3">
		<div class="element"></div>
	</div>
	<div class="col-1-3">
		<div class="element"></div>
	</div>
</div>

Z floatami jest niestety kilka problemów.
Pierwszym z nich jest to, że jeżeli wszystkie dzieci będą miały float (left lub right), wtedy rodzic straci wysokość.

https://codepen.io/kartofelek007/pen/jLGErb?editors=1100

Na naprawienie tego problemu jest kilka sposobów:

1) Najłatwiejszy to dodanie overflow:hidden/auto dla rodzica. Wygodny sposób, ale nie zawsze się sprawdzi. W takim rodzicu możemy mieć jakieś rozwijane menu, tooltipa itp. Wtedy ta metoda zwyczajnie zawiedzie, bo overflow:hidden ukryje ci rozwinięte menu, a overflow:auto sprawi, ze po rozwinięciu menu pojawią się paski przewijania.

https://codepen.io/kartofelek007/pen/XazKbQ

2) Dodanie .clearfix dla rodzica. Clearfix to po prostu dodatkowe style, które niwelują powyższy problem. Taki trik:

.clearfix::after {
    content: "";
    display: table;
    clear: both;
}

/* lub bezpośrednio dla rodzica */
.row::after {
    content: "";
    display: table;
    clear: both;
}

https://codepen.io/kartofelek007/pen/PKJQQb
https://codepen.io/kartofelek007/pen/jLarYQ

Teoretycznie najlepsza metoda, ale zdarzają się przypadki, że może nam ciut utrudnić życie (chociażby wtedy, gdy dla danego elementy z clearfix chcielibyśmy użyć ::after).

3) Trzeci sposób to dodanie elementu czyszczącego floaty (który ma właściwość clear:both) na końcu listy dzieci.

.clear {clear:both;}
<div class="row">
	<div class="col-1-3">
		<div class="element"></div>
	</div>
	<div class="col-1-3">
		<div class="element"></div>
	</div>
	<div class="col-1-3">
		<div class="element"></div>
	</div>
	<div class="clear"></div>
</div>

https://codepen.io/kartofelek007/pen/prWapL

Wydaje się, że jest to rozwiązanie najgorsze, bo przecież dochodzi nam dodatkowy znacznik. Niby tak – ale bardzo często będziemy musieli z niego korzystać. Omówię to poniżej.

Kolejny problem z jakim się spotkamy przy floatach, to układanie elementów po prawej stronie. Jeżeli zastosujemy float:right dla elementów, faktycznie przeskoczą na prawo, ale w odwrotnej kolejności.

https://codepen.io/kartofelek007/pen/wqrBgw?editors=1100

Żeby to naprawić, albo zmienimy ich kolejność w html (kiepsko), albo zastosujemy im display:inline-block a dla rodzica text-align:right (lub jedną z innych możliwości – np flex)

Kolejny – może nie tyle problem, co specyfika zachowania się samego floatu. Treść z boku floatowanego elementu opływa go. Jeżeli treść ta będzie dłuższa od elementu, przejdzie pod niego.

Żeby to zniwelować, dla treści musimy dać overflow:hidden;

https://codepen.io/kartofelek007/pen/NvwKEa

Overflow:hidden przyda nam się też przy naprawieniu zachowania się listy obok floatowanego elementu. Domyślnie lista wchodzi na taki element. Żadne paddingi i marginy tutaj nie pomogą – no chyba że damy je dla floatowanego elementu. Rozwiązaniem jest dać dla listy overflow:hidden.

https://codepen.io/kartofelek007/pen/YxrPEd

Na sam koniec problem niby błahy, a który może przyprawić nam kilka siwych włosów.
Jeżeli któryś z floatowanych dzieci będzie dłuższy od pozostałych, kolejne dzieci nie przeskoczą do nowej linii, tylko zatrzymają się na dłuższym bracie:

https://codepen.io/kartofelek007/pen/OjxPQJ

Jeżeli tworzymy nasz layout tak, że kolumny układamy w pojedyncze rzędy, a po zmniejszeniu kolumny te zamieniają się w elementy które mają 100% szerokości – raczej nie będzie problemu. Przykładem takiego bezproblemowego podejścia jest początkowy listing, gdzie mamy 3 kolumn które razem stanowią 1 rząd, a w odpowiedniej szerokości od razu robią się na 100%.
Nie będzie też problemu, gdy nasze floatowane kolumny będą miały na tyle miejsca, że ten tekst nie będzie ich rozpychał w pionie.

Problem pojawi się przy kolumnach, które muszą przeskakiwać do nowej linii (np z szerokości 25% zamieniają się na szerokość 50%) a treść ich jest zarządzana przez klienta i w żaden sposób nie ograniczana.

https://codepen.io/kartofelek007/pen/jLGZXx

Jak rozwiązać ten problem? Powyżej pokazałem ci 3 metodę rozwiązania problemu z wysokością rodzica poprzez zastosowanie dodatkowego elementu z clear:both. Taki element możemy też dać między odpowiednie kolumny, dzięki czemu resztę kolumn zmusimy do przeskoczenia poniżej. Taki element musimy w odpowiednim momencie (bp gdzie następuje zmiana szerokości kolumn) pokazać:

https://codepen.io/kartofelek007/pen/GvMQLW

Nie jest to rozwiązanie łatwe, bo często nie wiemy w sumie czy tekst w n-tym divie nie stanie się dłuższy przed zmianą szerokości elementów. Da się jednak tutaj czasami powalczyć. Przykład takiego rozwiązania znajdziemy też w bootstrapa w wersji 3 (przy czym oni wykorzystali do poprawy tego problemu trochę inne właściwości, ale idea jest ta sama)

display:inline-block

Drugim typem wyświetlania jaki chciałem dzisiaj omówić to display:inline-block.
Inline-block czyli niby inline a niby block – ogólnie coś pomiędzy.
Inline jak to inline – nadaje się do słów. Możemy nim pogrubić słowo (np strong), dać mu jakiś border, plus kilka podstawowych właściwości. Ale już np. marginesów pionowych nie damy, a padding będzie w odniesieniu do słowa (a nie jak normalnie w odniesieniu do górnego brzegu). Ogólnie więc display:inline wykorzystuje się raczej do pogrubiania czy zmiany koloru słów czy zdań w tekście. Jeżeli chcemy coś więcej podziałać, szybko wskakujemy na display:inline-block.

Block domyślnie zajmuje całą szerokość (to nie to samo co width:100%). Możemy tutaj nadawać wszystkie stylowania i wszystkie działają jak należy.

Inline-block leży gdzieś pomiędzy powyższymi. Działa jak block, ale domyślnie nie zajmuje pełnej szerokości, a dostosowuje szerokość do swojej zawartości. Działa tu też jak należy całe stylowanie – paddingi działają normalnie, możemy dodawać marginesy pionowe itp. Ten tryb wyświetlania najczęściej wykorzystywany jest do tworzenia poziomych list (dla LI) i buttonów:

https://codepen.io/kartofelek007/pen/zdEWGg
https://codepen.io/kartofelek007/pen/eEGMdw

W przeciwieństwie do floatów nie występuje tutaj problem z przeskakiwaniem elementów do nowej linii:

https://codepen.io/kartofelek007/pen/WEZzZY

Niestety tak jak i przy floatach tutaj też natraficie na pewne dziwactwa.
Pierwsze z nich wynika z tego, że inline-block jest „dzieckiem inline i blocka”. Z tego pierwszego odziedziczył „przerwę między słowami” (bo słowa mają między sobą przerwę). Zobacz na powyższe przykłady. Nie dawałem tym elementom żadnych marginesów, a mimo to jest między nimi przerwa.

Znowu – tak jak w przypadku floatów mamy kilka sposobów na rozwiązanie tego problemu.
Pierwszy z nich polega na takim zapisaniu html, by nie było między znacznikami spacji lub znaku nowej linii (enter). Możemy więc wszystko zapisać w jednej linii (w takim np twigu są nawet do tego osobne funkcje, lub też nieco zmodyfikować nasz kod:

.col {
	display:inline-block; 
	...
}	
<div class="row">
	<div class="col">
		<div class="element">
			element
		</div>
	</div><div class="col">
		<div class="element">
			element
		</div>
	</div><div class="col">
		<div class="element">
			element
		</div>
	</div>
</div>

https://codepen.io/kartofelek007/pen/PKOYzP

Drugą techniką jest odpowiednie zastosowanie komentarzy html, które zniwelują znak nowego wiersza:

<div class="row">
	<div class="col">
		<div class="element">
			element
		</div>
	</div><!--
	--><div class="col">
		<div class="element">
			element
		</div>
	</div><!--
	--><div class="col">
		<div class="element">
			element
		</div>
	</div>
</div>

https://codepen.io/kartofelek007/pen/ZJazyx

Trzecia metoda polega na ustawieniu dla rodzica font-size: 0, a następnie przywróceniu dla dzieci normalnego rozmiaru tekstu:

.row {
	font-size:0;
}
.row .col {
	font-size:1rem;
}

https://codepen.io/kartofelek007/pen/GvOKvp

Z tą metodą trzeba uważać, bo ponoć gdzieniegdzie może zawodzić a i SEO może się skarżyć.

Jest jeszcze jedna metoda, o której możecie usłyszeć. Polega ona na ustawieniu ujemnego margin-left dla dzieci. Nie będę się nią tutaj zajmował, bo nie bierze ona pod uwagę tego, że na różnych systemach tekst może być renderowany na różne sposoby, a więc i przerwa między elementami może być różna…

Przy pracy z inline-block natrafić można też na ciekawą rzecz. Chodzi dokładnie o działanie vertical-align. Jak wiecie (albo nie wiecie) w tabelach vertical-align (a w wersji dla atrybutów – valign) ustawia treść komórki w pionie:

https://codepen.io/kartofelek007/pen/ayVzEL?editors=1100

Admirale floty gwiezdnej – a po co mi taka prehistoryczna wiedza. Ano na przykład przyda się gdy będziesz tworzył swój najwspanialszy newsletter…

Nie ważne. Wracając do tematu – przy inline-block vertical-align działa inaczej. Tutaj elementy równane są w odniesieniu do najwyższego elementu w rzędzie:

https://codepen.io/kartofelek007/pen/vJWEav

Ciekawostka, która przyda się na rozmowach kwalifikacyjnych. Niby można to wykorzystać do centrowania elementu w pionie:

https://codepen.io/kartofelek007/pen/wqPBQv

ale technika ta jest „ciężka” w użyciu, a i w dzisiejszych czasach jest to przerost formy nad treścią – bo mamy flexa i jego trzy magiczne linijki…

.parent {
	display: flex;
	justify-content: center;
	align-items: center;
}	

https://codepen.io/kartofelek007/pen/LjObPg

Konkluzja

W powyższym artykule chciałem wam pokazać z czym można się zetknąć przy pracy z floatami i display:inline-block.
Jak widzicie nie są to idealne rozwiązania (a w zasadzie są idealne, ale w miejscach do których zostały stworzone). Dlatego właśnie ludzie wymyślili flexa i grida.
W dzisiejszych czasach używanie powyższych technik ma coraz bardziej „marginalne znaczenie” (jeżeli za marginalne brać 90% czy więcej stron w internecie).

W zasadzie można by powiedzieć, że dzięki flexowi (i gdy piszę te słowa – niedługo gridowi) float i display:inline-block wrócą na swoje należyte miejsce. Float – do wyciągania obrazków na daną stronę w teście, tak by tekst ładnie je oblewał. A display:inline-block – do tworzenia elementów ala buttony czy podobne cudeńka.
Ale by nie było – używanie ich w powyższy sposób nie jest żadnym błędem. Po prostu musimy się liczyć z koniecznością poprawy niektórych domyślnych zachowań. Dobry webmaster powinien to umieć, a przynajmniej powinien wiedzieć czego szukać na google-stacku…

Komentarze