Układ elastyczny

W tym rozdziale dowiesz się...

Wstęp

W zamierzchłych czasach sieci, gdy style CSS nie były jeszcze tak rozwinięte jak dzisiaj, rozplanowanie elementów na stronie realizowano się przy pomocy tabelek. Nie był to jednak najlepszy sposób, gdyż nie spełniał podstawowych zasad semantyki. Tabele zostały stworzone z myślą o prezentacji zbioru danych o powtarzającym się charakterze. Na szczęście style CSS wprowadziły nowe sposoby układania elementów na stronie, bez potrzeby używania w niewłaściwy sposób znaczników tabeli. Paradoksalnie właściwość position (pozycja) nie nadawała się zbytnio do ustalania głównego układu elementów na stronie, ponieważ wymagała, aby rozmiary bloków były z góry znane. W praktyce z taką sytuacją rzadko mamy do czynienia, gdyż nie jesteśmy w stanie od razu dokładnie przewidzieć, ile tekstu będą zawierać artykuły, opublikowane w serwisie.

Rozwiązaniem miało być płynne ustalanie pozycji przy pomocy właściwości float [zobacz: Szablon strony na DIV-ach]. I rzeczywiście w większości typowych zastosowań taki sposób był zupełnie wystarczający. Niestety w pewnych szczególnych przypadkach miał podobne ograniczenia jak pozycja absolutna. Bardzo trudno było zrealizować, zdawać by się mogło, tak trywialne sposoby układania elementów, jak wyśrodkowanie w pionie czy ustawienie kilku kolumn obok siebie przy zachowaniu takiej samej ich wysokości. W niektórych sytuacjach cierpiała na tym dostępność serwisu. Syntezatory mowy, stosowane w przeglądarkach używanych przez osoby niewidome, odczytują treść strony w kolejności jej występowanie w kodzie źródłowym HTML, a nie wizualnego ułożenia bloków na ekranie. Dlatego często korzystniej jest, aby najpierw w kodzie umieścić treść artykułu, a dopiero po niej rozbudowane menu nawigacyjne. Niestety w takiej sytuacji nie można było stworzyć prawdziwie elastycznego układu strony, z kolumną menu po lewej stronie, a treścią artykułu zajmującą całą wolną przestrzeń po prawej.

Na szczęście CSS3 rozwiązuje ten problem. Nie trzeba już stosować tabelek, pozycji absolutnych ani trików z płynnym układaniem elementów. Dzięki koncepcji układu elastycznego (ang. flexible box layout) dostajemy zaawansowane możliwości rozplanowania bloków na stronie, przy jednoczesnym automatycznym dopasowywaniu się całego układu, tak aby dokładnie spełniał nasze oczekiwania, bez względu na ilość treści w poszczególnych blokach na stronie.

Kontener elastyczny

(CSS 3 - interpretuje Internet Explorer 10, Firefox, Opera 12, Chrome)

  1. Układ elastyczny w bloku:
    selektor { display: flex }
  2. Układ elastyczny w linii:
    selektor { display: inline-flex }
Wstawienie jednej z powyższej deklaracji sprawia, że dzieci elementu (znaczniki które bezpośrednio się w nim zawierają), wyznaczonego podanym selektorem [zobacz: Wstawianie stylów], będą układane w nim w sposób elastyczny.

Tak tworzy się tzw. kontener elastyczny (ang. flex container), w którym dzieci układane są elastycznie. Sam kontener nie jest układany elastycznie na stronie, a jedynie jego dzieci. Wstawienie takiego kontenera przełącza tryb wyświetlania elementów w nim zawartych na układ elastyczny.

Aby jakiekolwiek własności, opisane dalej w tym rozdziale, dały widoczny efekt, konieczne jest dodanie powyższego stylu do elementu, który ma wyznaczać układ elastyczny.

Przepływ

(CSS 3 - interpretuje Internet Explorer 10, Firefox, Opera 12, Chrome)

Kierunek

selektor { flex-direction: kierunek }
Selektorem musi być kontener elastyczny.

Kierunek określa sposób układania kolejnych elementów wewnątrz układu elastycznego:
  • row - elementy będą układane w wierszach, analogicznie jak wyrazy tekstu w akapitach (domyślnie)
  • row-reverse - ułożenie w wierszach w przeciwnym kierunku (w języku polskim będzie to od prawej do lewej krawędzi kontenera)
  • column - ułożenie pionowo w kolumnach (w języku polskim - od góry do dołu)
  • column-reverse - ułożenie pionowo w kolumnach (w języku polskim - od dołu do góry)

Polecenie pozwala sterować ułożeniem bloków w sposób podobny do wyrazów w tekście akapitu. Wyrazom jednak nie możemy nadawać rozmiarów, a blokom w układzie elastycznym - tak.

Zawijanie

selektor { flex-wrap: zawijanie }
Selektorem musi być kontener elastyczny.

Zawijanie:
  • nowrap - elementy nie zostaną zawinięte do kolejnego wiersza, nawet jeśli nie zmieszczą się w dostępnej szerokości kontenera (domyślnie)
  • wrap - elementy, które nie zmieszczą się w dostępnej szerokości, zostaną przeniesione do kolejnego wiesza, jak wyrazy tekstu
  • wrap-reverse - niemieszczące się elementy będą przeniesione do wcześniejszego wiersza (w języku polskim wyglądało by to tak, jakbyśmy pisali tekst w wierszach, zaczynając od dołu kartki papieru)

Polecenie pozwala sterować ułożeniem wierszy bloków w sposób podobny do linii w tekście akapitu.

Atrybuty mieszane

selektor { flex-flow: wartości atrybutów }

Polecenie to pozwala od razu podać kierunek i zawijanie elementów w układzie elastycznym.

Przykład:

"flex-flow: row nowrap" - zwróć uwagę, że wszystkie elementy są identycznej wysokości:

To jest
blok nr 1
blok 2
blok 3
blok 4
blok 5

"flex-flow: row wrap" - zwróć uwagę, że wysokość bloków dopasowuje się automatycznie w każdym osobnym wierszu układu:

To jest
blok nr 1
blok 2
blok 3
blok 4
blok 5

flex-flow: row-reverse nowrap

To jest
blok nr 1
blok 2
blok 3
blok 4
blok 5

flex-flow: row-reverse wrap-reverse

blok 1
blok 2
blok 3
blok 4
blok 5

Kolejność

(CSS 3 - interpretuje Internet Explorer 10, Firefox, Opera 12, Chrome)

selektor { order: kolejność }
Selektorem mogą być dzieci kontenera elastycznego (ale nie sam kontener).

Natomiast kolejność to liczba całkowita, domyślnie równa zero. Elementy z przypisaną niższą wartością, będą wyświetlane w pierwszej kolejności. Wartości ujemne pozwalają przesunąć dowolny element na miejsce przed pierwszym. Elementy z przypisaną taką samą liczbą, wyświetlą się w kolejności ich występowania w kodzie źródłowym HTML.

Możliwość swobodnego ustalania kolejności wyświetlania się elementów to następna duża zaleta układu elastycznego. Przy wstawiania znaczników HTML do kodu źródłowego już nie musimy się martwić, aby były one osadzone w kolejności odpowiedniej do ich poprawnego wyświetlenia - zgodnie z zaprojektowaną grafiką serwisu.

Dzięki temu możemy tworzyć bardziej dostępne dokumenty. Przykładowo dla osoby niewidomej, która używa przeglądarki z syntezatorem mowy, prawdopodobnie korzystniej będzie, jeśli zapoznając się z katalogiem produktów w sklepie internetowym, najpierw usłyszy informacje o nazwie produktu, a potem jego opis. Zdjęcie jest w tym przypadku zupełnie nieważne, dlatego najlepiej jest wstawić je na końcu. Jednak dla użytkowników z dobrym wzrokiem właśnie zdjęcie może okazać się najważniejsze. Umieszczając je w kontenerze elastycznym, a następnie określając dla niego styl "order: -1", wyświetlimy go na początku, podczas gdy syntezator mowy trafi na niego dopiero na końcu. W ten sposób potrzeby obu grup użytkowników zostaną spełnione.

Przykład:

blok 1
blok 2
blok 3 (order: -1)
blok 4
blok 5

Poniżej przykład fragmentu szablonu strony, który spełnia założenia dostępności - treść znajduje się w kodzie źródłowym przed kolumną menu. Mimo tego szerokość automatycznie dopasowuje się do okna przeglądarki. Dodatkowo warto zwrócić uwagę, że wysokość obu kolumn jest identyczna. Uzyskanie takiego efektu w tradycyjny sposób byłoby bardzo trudne i najczęściej wymagało pójścia na pewne kompromisy.

<div id="top">
	<div id="TRESC">Treść strony...</div>
	<div id="MENU">Menu nawigacyjne</div>
</div>
#top {
	display: flex;
}

#MENU {
	width: 150px;
	min-width: 150px;
	order: -1;
}

[porównaj: Płynny szablon]

Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony... Treść strony...
Menu nawigacyjne

Elastyczność

(CSS 3 - interpretuje Internet Explorer 10, Firefox, Opera 12, Chrome)

Rozciągnięcie

selektor { flex-grow: rozciągnięcie }
Selektorem mogą być dzieci kontenera elastycznego (ale nie sam kontener).

Rozciągnięcie jest wyrażone liczbą naturalną (większą lub równą zero), która określa proporcje, w jakich będą rozciągane elementy w kontenerze. Domyślna wartość - zero - odbiera elementom elastyczność.

Może się zdarzyć, że w jednym wierszu kontenera elastycznego mogłoby się zmieścić więcej elementów niż mamy zapewnionych. Wtedy zwykle z prawej strony pozostaje wolna przestrzeń. Możemy jednak sprawić, aby w takiej sytuacji szerokość elementów elastycznie dopasowała się w taki sposób, aby wypełniły całą dostępną przestrzeń kontenera. Jeżeli chcemy, aby wszystkie elementy zostały rozciągnięte równomiernie, wystarczy każdemu przypisać styl "flex-grow: 1". Możemy też zadecydować, aby np. jeden z nich rozszerzył się dwa razy bardziej niż inne - przypisujemy mu wartość "flex-grow: 2". Istnieje również możliwość ustalenia, aby tylko jeden element wypełnił całą pozostałą wolną przestrzeń w kontenerze. Wtedy tylko jemu nadajemy styl "flex-grow: 1".

Ściśnięcie

selektor { flex-shrink: ściśnięcie }
Selektorem mogą być dzieci kontenera elastycznego (ale nie sam kontener).

Ściśnięcie jest wyrażone liczbą naturalną (większą lub równą zero), która określa proporcje, w jakich będą ściskane elementy w kontenerze (domyślnie - "1").

Jeżeli kontener elastyczny jest zbyt wąski, jego dzieci są ściskane. Zwykle odbywa się to poprzez przełamanie do nowej linii tekstu, który zawiera się w tych blokach.

Baza

selektor { flex-basis: baza }
Selektorem mogą być dzieci kontenera elastycznego (ale nie sam kontener).

Baza jest wartością określoną w jednostkach długości albo słowem kluczowym "auto" (domyślnie).

Baza określa początkowy rozmiar elementu w kontenerze, zanim wolna przestrzeń zostanie rozłożona pomiędzy dzieci kontenera.

Wartość "0" (zero) spowoduje, że rozmiary elementów będą bezpośrednio proporcjonalne do przypisanych im wartości flex-grow (albo flex-shrink - w przypadku ściśnięcia). Jeżeli wszystkie elementy kontenera będą miały przypisany styl "flex-grow: 1", w efekcie mogą zostać rozciągnięte do dokładnie takiego samego rozmiaru.

Wartość "auto" (domyślnie) spowoduje, że rozmiary absolutne poszczególnych elementów mogą nie być równe, ponieważ wolna przestrzeń rozłoży się proporcjonalnie tylko po bokach wewnątrz elementów.

Wartość "auto" rozkłada wolną przestrzeń równomiernie po bokach elementów, a "0" - na całych ich rozmiarach.

Powyższy diagram przedstawia różnice między "absolutną" (baza zerowa) a "relatywną" (baza zależna od zawartości elementów) elastycznością. Kolejne elementy w poszczególnych kontenerach elastycznych mają przypisaną wartość flex-grow odpowiednio: 1, 1, 2.

Źródło: CSS Flexible Box Layout Module

Atrybuty mieszane

selektor { flex: wartości atrybutów }

Polecenie to pozwala od razu podać rozciągnięcie, ściśnięcie i bazę elementów w układzie elastycznym. Każda z wartości jest opcjonalna, przy czym jeśli chcemy podać flex-shrink, należy obowiązkowo poprzedzić ją wartością flex-grow. Nie ma możliwości określenia w ten sposób samego ściśnięcia bez ustalania rozciągnięcia. Ponadto jeśli chcemy określić zerową długość flex-basis, trzeba koniecznie dopisać do niej jednostkę. Choć normalnie jednostka przy wartości zero nie jest wymagana, tutaj zapobiega omyłkowemu uznaniu długości bazy za rozciągnięcie lub ściśnięcie. Jednostkę można pominąć tylko, kiedy w deklaracji występują wszystkie trzy wartości.

Jako wartości atrybutów można wpisać również samo słowo kluczowe "none", co odpowiada: "0 0 auto" ("flex-grow: 0; flex-shrink: 0; flex-basis: auto"). Warto zauważyć, że domyślna wartość tych atrybutów jest inna - "0 1 auto".

Z uwagi na fakt, że składnia tego polecenia przewiduje najczęstsze przypadki użycia, zaleca się stosować zawsze atrybuty mieszane zamiast osobnych poleceń.

Przykład:

none
flex: none
none

1 0px
flex: 1 0px
2 0px

1 auto
flex: 1 auto
2 auto

1 1 auto
flex: 1 1 auto
1 2 auto

Marginesy automatyczne

(CSS 3 - interpretuje Internet Explorer 10, Firefox, Opera 12, Chrome)

selektor { margin-top: auto }
selektor { margin-right: auto }
selektor { margin-bottom: auto }
selektor { margin-left: auto }
selektor { margin: auto }
Selektorem mogą być dzieci kontenera elastycznego.

Ustawiając wybrany margines na wartość automatyczną sprawimy, że wypełni on wolną przestrzeń pozostałą w kontenerze. Dzięki temu w bardzo prosty sposób możemy ustawić kilka bloków w jednej linii - część przy lewej krawędzi, a niektóre przy prawej.

Przykład:

blok 1
blok 2
blok 3
margin-left: auto

Justowanie zawartości

(CSS 3 - interpretuje Internet Explorer 10, Firefox, Opera 12, Chrome)

selektor { justify-content: justowanie }
Selektorem może być kontener elastyczny.

Justowanie:
  • flex-start - do początkowej krawędzi kontenera (domyślnie)
  • flex-end - do końcowej krawędzi kontenera
  • center - wyśrodkowanie
  • space-between - równe odstępy między elementami
  • space-around - równa przestrzeń wokół elementów

Polecenie steruje justowaniem elementów kontenera elastycznego, gdy jest on zbyt duży, aby został wypełniony w całości. Działa analogicznie jak justowanie tekstu, ale może operować na blokach.

Przykład:

justify-content: flex-start

blok 1
blok 2
blok 3

justify-content: flex-end

blok 1
blok 2
blok 3

justify-content: center

blok 1
blok 2
blok 3

justify-content: space-between

blok 1
blok 2
blok 3

justify-content: space-around

blok 1
blok 2
blok 3

Wyrównanie wiersza

(CSS 3 - interpretuje Internet Explorer 10, Firefox, Opera 12, Chrome)

Wspólne

selektor { align-items: wyrównanie }
Selektorem może być kontener elastyczny.

Wyrównanie:
  • flex-start - wyrównanie wiersza do początkowej krawędzi kontenera
  • flex-end - do końcowej krawędzi kontenera
  • center - wyśrodkowanie wiersza (dla tekstu w języku polskim - w pionie)
  • baseline - zrównanie linii bazowych (poziomych prostych, łączących podstawy liter tekstu)
  • stretch - rozciągnięcie do obu krawędzi jednocześnie (domyślnie)

Polecenie steruje wyrównaniem jednego wiersza wewnątrz kontenera elastycznego, kiedy mają one różną wysokość.

Przykład:

align-items: flex-start

To jest
blok nr 1
blok 2
blok 3

align-items: flex-end

To jest
blok nr 1
blok 2
blok 3

"align-items: center" - ten sposób pozwala wyśrodkować w pionie element, nawet jeżeli z góry nie wiemy, ile treści będzie się w nim znajdować:

To jest
blok nr 1
blok 2
blok 3

align-items: baseline

blok 1
blok 2
blok 3

align-items: stretch

To jest
blok nr 1
blok 2
blok 3

Indywidualne

selektor { align-self: wyrównanie }
Selektorem mogą być dzieci kontenera elastycznego (ale nie sam kontener)..

Jako wyrównanie należy podać jedną z wartości - analogicznie jak w przypadku wspólnego wyrównania. Oprócz tego można ustawić wartość "auto" (domyślnie), która oznacza przejęcie sposobu wyrównania z kontenera.

Wyrównanie indywidualne pozwala ustawić w różny sposób każdy z elementów kontenera elastycznego. Jeżeli jednak wszystkie mają być wyrównane tak samo, korzystniej będzie zrobić to dla nich wspólnie.

Wyrównanie wierszy

(CSS 3 - interpretuje Internet Explorer 10, Firefox, Opera 12, Chrome)

selektor { align-content: wyrównanie }
Selektorem może być kontener elastyczny, którego elementy zostały ułożone w wielu wierszach.

Wyrównanie:
  • flex-start - wyrównanie wierszy do początkowej krawędzi kontenera
  • flex-end - do końcowej krawędzi kontenera
  • center - wyśrodkowanie wierszy (dla tekstu w języku polskim - w pionie)
  • space-between - równe odstępy między wierszami
  • space-around - równa przestrzeń wokół wierszy
  • stretch - rozciągnięcie wierszy do obu krawędzi jednocześnie (domyślnie)

Polecenie steruje wyrównaniem wielu wierszy wewnątrz kontenera elastycznego, kiedy ich sumaryczna wysokość jest za mała, aby wypełnić całą dostępną przestrzeń.

Przykład:

align-content: flex-start

blok 1
blok 2
blok 3
blok 4
blok 5

align-content: flex-end

blok 1
blok 2
blok 3
blok 4
blok 5

align-content: center

blok 1
blok 2
blok 3
blok 4
blok 5

align-content: space-between

blok 1
blok 2
blok 3
blok 4
blok 5

align-content: space-around

blok 1
blok 2
blok 3
blok 4
blok 5

align-content: stretch

blok 1
blok 2
blok 3
blok 4
blok 5