CSS3 - Elastyczny układ elementów HTML

W poprzednich częściach tego kursu CSS poznaliśmy kilka sposób na wyświetlenie kilku blokowych elementów HTML obok siebie. Przeważnie każdy sposób zawierał pewne niedogodności lub wymagał od nas zdobycia dodatkowej wiedzy oraz umiejętności, dlatego mogliśmy zadać sobie pytanie: Dlaczego ułożenie dwóch blokowych elementów HTML jest tak dziwną i czasami skomplikowaną czynnością? Pewnie twórcy języka CSS również to zauważyli, dlatego wraz z rozwojem specyfikacji CSS3 zostały do niej dodane właściwości CSS, które są przeznaczone dla elastycznych elementów HTML, czyli takich, których sposób wyświetlenia określa właściwość display wraz z wartością flex lub inline-flex. Na razie skupimy się na wartości flex.

Gdy umieścimy kilka elementów HTML w innym elemencie HTML, tworzą one układ rodzic oraz dzieci. Gdy dzieci danego elementu HTML są elementami blokowymi (domyślnie display:block;) to wspomniane elementy HTML wyświetlają się jeden pod drugim oraz ich szerokość dopasowuje się automatycznie do szerokości ich elementu rodzica (uwzględniając przy tym jego marginesy wewnętrzne, czyli właściwość padding).

Przykład:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Darmowy Kurs CSS</title>

    <style>
      #rodzic {
        background-color:#DFF;
        padding:5px;
      }

      #rodzic > div {
        background-color:#5DD;
        margin:10px;
        padding:5px;
      }
    </style>
  </head>

  <body>

    <div id="rodzic">
      <div id="div1">div - 1</div>
      <div id="div2">div - 2</div>
      <div id="div3">div - 3</div>
    </div>

  </body>
</html>

Rezultat:

div - 1
div - 2
div - 3

Nasz kod HTML nie zawiera niczego szczególnego. Widzimy w nim kilka blokowych elementów div umieszczonych w innym elemencie div (od tej pory ten element HTML będę nazywał #rodzic, a jego dzieci: #div1, #div2, #div3, jeśli zajdzie taka potrzeba (tak samo jak wartości ich atrybutu id)). Do wspomnianych elementów HTML zostały dodane przykładowe właściwości CSS, które określają ich kolor tła (background-color), marginesy zewnętrzne (margin), marginesy wewnętrzne (padding).

Tak jak mogliśmy się spodziewać, blokowe dzieci elementu #rodzic zostały wyświetlone jeden pod drugim. Zobaczmy co się stanie, gdy do elementu #rodzic dodamy właściwość display wraz z wartością flex.

#rodzic {
  display:flex;
  background-color:#DFF;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

Od tej pory dzieci elementu #rodzic tworzą wraz z nim układ elastyczny, ponieważ do elementu #rodzic została dodana właściwość display wraz z wartością flex. Domyślnie dzieci elastycznego elementu HTML (czyli elementu z właściwością display:flex;) wyświetlają się jeden obok drugiego podobnie gdy osiągaliśmy ten sam efekt, wykorzystując do tego celu właściwość float, jednak tym razem wszystko jest w porządku (nie musimy rozwiązywać żadnych dodatkowych problemów, jak miało to miejsce w przypadku właściwości float).

W tym momencie mógłbym zakończyć tę część kursu CSS, jednak to dopiero początek "zabawy" z elastycznym układem elementów HTML, ponieważ dla wspomnianego układu zostały stworzone dodatkowe właściwości CSS, które mogą kontrolować wiele dodatkowych cech wyglądu elastycznego układu elementów HTML. Wspomniane właściwości CSS zostały umieszczone przeze mnie w kategorii Elastyczność. Wspomniane właściwości CSS zostaną przedstawione w kolejnych akapitach tej części kursu CSS.

Pierwszą interesującą właściwością dla elastycznego układu elementów HTML jest właściwość order. Jest ona przeznaczona dla dzieci elastycznego układu elementów HTML. Za pomocą właściwości order możemy zmienić kolejność wyświetlania się dzieci elastycznego układu elementów HTML nie ingerując w zmianę kolejności elementów w kodzie HTML.

Przykład:

#div1 {
  order:3;
}

#div2 {
  order:1;
}

#div3 {
  order:2;
}

Rezultat:

div - 1
div - 2
div - 3

Od tej pory element #div1 wyświetla się jako trzeci (order:3;), element #div2 jako pierwszy (order:1;), a element #div3 jako drugi element elastycznego układu elementów HTML (order:2;). W przypadku, gdy dzieci elastycznego układu elementów HTML zawierają właściwość order z tą samą wartością, kolejność ich wyświetlenia się określa kolejność jaką zajmują one w kodzie HTML.

Przyglądając się naszemu elastycznemu układowi elementów HTML możemy dojść do wniosku, że szerokość jego elementów dzieci jest uzależniona od zawartości jaką umieścimy we wspomnianych elementach dzieciach. Domyślnie dzieci elastycznego układu elementów HTML wyświetlają się w poziomie. Gdy ich zawartość jest zbyt mała, w poziomie tworzy się pusta przestrzeń (po prawej stronie ostatniego dziecka elastycznego układu elementów HTML). Na podstawie wartości tej pustej przestrzeni jest obliczana proporcja rozrostu szerokości poszczególnych dzieci elastycznego układu elementów HTML, gdy postanowimy skorzystać z właściwości flex-grow.

Przykład:

#div1 {
  flex-grow:1;
}

#div2 {
  flex-grow:2;
}

#div3 {
  flex-grow:3;
}

Rezultat:

div - 1
div - 2
div - 3

Nasz elastyczny układ elementów HTML składa się z trzech elementów dzieci, do których została dodana właściwość flex-grow wraz z wartością 1 (dla #div1), 2 (dla #div2) oraz 3 (dla #div3). Oznacza to, że proporcja rozrostu szerokości poszczególnych dzieci elastycznego układu elementów HTML wynosi 1:2:3, dlatego powiększona szerokość elementu #div2 jest dwa razy większa od powiększonej szerokości elementu #div1 (jak proporcja 1:2), natomiast powiększona szerokość elementu #div3 jest trzy razy większa od powiększonej szerokości elementu #div1 (jak proporcja 1:3).

Jedną z kolejnych właściwości przeznaczonych dla elastycznego układu elementów HTML jest właściwość, która domyślnie określa rozmiar szerokości elementu dziecka elastycznego układu elementów HTML. Właściwością tą jest właściwość flex-basis.

Przykład:

#div1 {
  flex-basis:30%;
}

#div2 {
  flex-basis:50%;
}

#div3 {
  flex-basis:40%;
}

Rezultat:

div - 1
div - 2
div - 3

Do trzech elementów dzieci elastycznego układu elementów HTML została dodana właściwość flex-basis wraz z wartością 30% (dla #div1), 50% (dla #div2) oraz 40% (dla #div3). Właściwość flex-basis określiła wartość szerokości dla poszczególnych elementów dzieci elastycznego układu elementów HTML. Suma tych wartości wynosi 120% (30% + 50% + 40% = 120%), dlatego możemy się trochę dziwić dlaczego ostatni element dziecko elastycznego układu elementów HTML nie został umieszczony w następnym wierszu pod dwoma pierwszymi elementami dziećmi. Dzieje się tak, ponieważ domyślnie w elastycznym układzie elementów HTML, gdy szerokość dzieci wspomnianego układu przekracza rozmiar szerokości ich rodzica, wartości szerokości elementów dzieci są odpowiednio ściskane (zmniejszane). Proporcje ściskania możemy kontrolować za pomocą właściwości flex-shrink.

Przykład:

#div1 {
  flex-basis:50%;
  flex-shrink:1;
}

#div2 {
  flex-basis:50%;
  flex-shrink:2;
}

#div3 {
  flex-basis:50%;
  flex-shrink:1;
}

Rezultat:

div - 1
div - 2
div - 3

Dla trzech elementów dzieci elastycznego układu elementów HTML została ustalona szerokość o wartości 50%. Suma wszystkich wartości szerokości elementów dzieci elastycznego układu elementów HTML wynosi 150% (50% + 50% + 50%). Jest to więcej o 50% niż szerokość ich wspólnego elementu rodzica, którego szerokość wynosi 100%, dlatego szerokości wszystkich elementów dzieci elastycznego układu elementów HTML zostały odpowiednio ściśnięte (zmniejszone). Proporcje tych ściśnięć zostały ustalone za pomocą właściwości flex-shrink o wartości 1 (dla #div1), 2 (dla #div2) oraz 1 (dla #div3), dlatego element #div2 jest bardziej ściśnięty od pozostałych elementów dzieci elastycznego układu elementów HTML.

Jeżeli chcemy skorzystać z jednej właściwości CSS, która określi flex-grow, flex-shrink oraz flex-basis to możemy wykorzystać do tego celu właściwość flex.

Domyślnie w przypadku gdy szerokość elementów dzieci elastycznego układu elementów HTML w sumie przekracza wartość ich wspólnego elementu rodzica, szerokości wspomnianych elementów dzieci są odpowiednio ściskane, lecz możemy również sprawić, że elementy dzieci niemieszczące się w tym samym wierszu zostaną przełamane, czyli umieszczone w następnym wierszu. Do kontrolowania tej cechy wyglądu służy właściwość flex-wrap. Należy ją dodać do elementu rodzica elastycznego układu elementów HTML.

Przykład:

#rodzic {
  flex-wrap:wrap;
  background-color:#DFF;
  padding:5px;
}

#rodzic > div {
  flex-basis:40%;
  background-color:#5DD;
  margin:10px;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

Dla trzech elementów dzieci elastycznego układu elementów HTML została ustalona szerokość o wartości 40%. Suma wszystkich wartości szerokości elementów dzieci elastycznego układu elementów HTML wynosi 120% (40% + 40% + 40%). Jest to więcej o 20% niż szerokość ich wspólnego elementu rodzica, którego szerokość wynosi 100%. Elementy dzieci elastycznego układu elementów HTML zostały przełamane (umieszczone w osobnych poziomych wierszach), ponieważ do ich wspólnego elementu rodzica została dodana właściwość flex-wrap wraz z wartością wrap.

Kolejną właściwością CSS, która jest przeznaczona dla elastycznego układu elementów HTML, jest właściwość justify-content. Za pomocą wspomnianej właściwości justify-content domyślnie możemy kontrolować poziome wyrównanie wszystkich dzieci elastycznego układu elementów HTML, np. możemy wyśrodkować wspomniane elementy dzieci elastycznego układu elementów HTML.

Przykład:

#rodzic {
  flex-wrap:wrap;
  justify-content:center;
  background-color:#DFF;
  padding:5px;
}

#rodzic > div {
  flex-basis:40%;
  background-color:#5DD;
  margin:10px;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

Natomiast za pomocą właściwości align-content możemy wykonać tą samą czynność, lecz względem pionu (należy również ustalić jakąś większą wartość wysokości elementu rodzica elastycznego układu elementów HTML).

Przykład:

#rodzic {
  flex-wrap:wrap;
  align-content:center;
  height:300px;
  background-color:#DFF;
  padding:5px;
}

#rodzic > div {
  flex-basis:40%;
  background-color:#5DD;
  margin:10px;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

Gdy dzieci naszego elastycznego układu elementów HTML są wyświetlone w jednym wierszu, a wysokość rodzica wspomnianych dzieci elastycznego elementu HTML jest większa niż wartość wysokości wspomnianych elementów dzieci, wartość wysokości tych dzieci jest rozciągana wraz z ich wspólnym rodzicem.

Przykład:

#rodzic {
  height:300px;
  background-color:#DFF;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

W tym momencie możemy skorzystać z właściwości align-items, która działa podobnie jak właściwość align-content.

Przykład:

#rodzic {
  align-items:center;
  height:300px;
  background-color:#DFF;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

Właściwość align-items różni się od właściwości align-content tym, że właściwość align-content wyrównuje elementy dzieci elastycznego układu elementów HTML względem wysokości ich wspólnego elementu rodzica, natomiast właściwość align-items dokonuje tego samego wyrównania w pionie, jednak względem wysokości wiersza, w którym znalazły się dane elementy dzieci elastycznego układu elementów HTML, tak jak w przykładzie zaprezentowanym poniżej.

Przykład:

#rodzic {
  flex-wrap:wrap;
  align-items:center;
  height:300px;
  background-color:#DFF;
  padding:5px;
}

#rodzic > div {
  flex-basis:40%;
  background-color:#5DD;
  margin:10px;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

Jeżeli chcemy dokonać wyrównania w pionie na konkretnym elemencie dziecku elastycznego układu elementów HTML, możemy skorzystać z właściwości align-self.

Przykład:

#rodzic {
  height:300px;
  background-color:#DFF;
  padding:5px;
}

#div2 {
  align-self:center;
}

Rezultat:

div - 1
div - 2
div - 3

Jak wiemy, domyślnie, elastyczny układ elementów HTML prezentuje nam jego elementy dzieci wyświetlone w poziomie (tzw. orientacja pozioma).

Przykład:

div - 1
div - 2
div - 3

Jeżeli chcemy, aby dzieci elastycznego układu elementów HTML były wyświetlone w pionie (w kolumnach, tzw. orientacja pionowa) możemy skorzystać z właściwości flex-direction.

Przykład:

#rodzic {
  flex-direction:column;
  height:300px;
  background-color:#DFF;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

Uwaga Gdy zmieniamy domyślną poziomą orientację elementów dzieci elastycznego układu elementów HTML na pionową, zmieniają się również sposób działania poszczególnych właściwości przeznaczonych dla elastycznego układu elementów HTML, przykładowo, jeżeli właściwość flex-basis określała wartość szerokości elementów dzieci elastycznego układu elementów HTML wyświetlonego w orientacji poziomej, tak dla orientacji pionowej będzie ona określała wartość wysokości, a nie wartość szerokości wspomnianych elementów dzieci elastycznego układu elementów HTML (ich rozrost oraz ściśnięcie również będzie tyczyło się wysokości, właściwości służące do wyrównania w poziomie od tej pory będą wyrównywać w pionie elementy dzieci elastycznego układu elementów HTML, natomiast właściwości służące do wyrównania w pionie od tej pory będą wyrównywać w poziomie elementy dzieci elastycznego układu elementów HTML).

Przykład:

#rodzic {
  flex-direction:column;
  height:300px;
  background-color:#DFF;
  padding:5px;
}

#rodzic > div {
  flex-basis:15%;
  background-color:#5DD;
  margin:10px;
  padding:5px;
}

Rezultat:

div - 1
div - 2
div - 3

W przykładzie zaprezentowanym powyżej, właściwość flex-basis określa wartość wysokości poszczególnych elementów dzieci elastycznego układu elementów HTML, ponieważ zostały one wyświetlone w orientacji pionowej, dzięki właściwości flex-direction oraz wartości column, które zostały dodane do elementu #rodzic.

Jeżeli chcemy skorzystać z jednej właściwości CSS, która określi flex-direction oraz flex-wrap to możemy wykorzystać do tego celu właściwość flex-flow.

Na początku tej części kursu CSS dowiedzieliśmy się, że oprócz wartości flex, która określa, wraz z właściwością display, elastyczny układ elementów HTML, istnieje również wartość inline-flex. Wartość inline-flex pozwala nam wyświetlić kilka elastycznych układów elementów HTML obok siebie.

Przykład:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Darmowy Kurs CSS</title>

    <style>
      .rodzic {
        display:inline-flex;
        display:-webkit-inline-flex;
        width:40%;
        background-color:#DFF;
        padding:5px;
      }

      .rodzic > div {
        background-color:#5DD;
        margin:10px;
        padding:5px;
      }
    </style>
  </head>

  <body>

    <div class="rodzic">
      <div>div - 1</div>
      <div>div - 2</div>
      <div>div - 3</div>
    </div>

    <div class="rodzic">
      <div>div - 1</div>
      <div>div - 2</div>
      <div>div - 3</div>
    </div>

  </body>
</html>

Rezultat:

div - 1
div - 2
div - 3
div - 1
div - 2
div - 3

W następnej części kursu CSS poznamy dodatkowe wymogi, które czasami musimy spełnić, gdy chcemy użyć daną właściwość CSS.