Problemy poziomego menu CSS

W poprzedniej części kursu CSS dowiedzieliśmy się w jaki sposób możemy sprawić, aby elementy naszego poziomego menu CSS zostały wyświetlone obok siebie. Wykorzystaliśmy do tego celu właściwość float. Właściwość float pomogła nam w wyświetleniu kilku blokowych elementów HTML obok siebie, jednak korzystanie z tej właściwości CSS może przysporzyć nam pewnych problemów, które zostaną omówione i rozwiązane w tej części kursu CSS.

Zerowa wysokość elementu rodzica

Wygląd naszego poziomego menu CSS, jak do tej pory, prezentował się następująco:

Kod HTML:

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

    <style>
      /* wygląd elementu - ul */
      ul {
        margin:0;
        padding:0;
        list-style-type:none;
        border:1px solid #000;
      }

      /* wygląd elementów - li */
      ul > li {
        float:left;
      }

      /* wygląd nieparzystych elementów - li elementu - ul */
      ul > li:nth-child(odd) {
        background-color:gold;
      }

      /* wygląd parzystych elementów - li elementu - ul */
      ul > li:nth-child(even) {
        background-color:lightblue;
      }

      /* wygląd elementów - a */
      ul > li > a {
        display:block;
        text-decoration:none;
        color:#000;
      }
    </style>
  </head>

  <body>

    <ul>
      <li><a href="#">link - 1</a></li>
      <li><a href="#">link - 2</a></li>
      <li><a href="#">link - 3</a></li>
    </ul>

  </body>
</html>

Nasze poziome menu CSS składa się z elementów ul oraz li. Elementy li zostały wyświetlone obok siebie, ponieważ została do nich dodana właściwość float, o czym była mowa w poprzedniej części tego działu kursu CSS.

Wysokość elementu ul jest zerowa (2px wysokości stanowi jego pomocnicze czarne obramowanie), ponieważ jego zawartością są tylko elementy unoszące się (elementy li wraz z właściwością float). Jednym ze sposobów na to, aby wysokość elementu rodzica, który zawiera w swojej zawartości tylko elementy unoszące się, które są jego dziećmi, nie wynosiła 0, jest dodanie do końcowej zawartości elementu rodzica unoszących się elementów HTML (w naszym wypadku tym elementem jest element ul) dodatkowego elementu HTML wraz z właściwością clear oraz wartością both, o czym była mowa w dziale pierwszym - Technika clearfix, floatfix.

Problem polega na tym, że dziećmi elementu ul mogą być tylko i wyłącznie elementy li (elementy ul wraz z elementami li tworzą listę HTML, która jest nam potrzebna do budowy naszego poziomego menu CSS), dlatego nasz problem zerowej wysokości elementu ul musimy rozwiązać w nieco inny sposób. Dodamy do końcowej zawartości wspomnianego elementu ul dodatkowy element HTML w formie zawartości generowanej tylko do odczytu (za pomocą selektora :after oraz właściwości content), o czym była mowa w dziale pierwszym - Dodatkowy element HTML.

ul:after {
  content:'dodatkowa zawartość';
  display:block;
  clear:both;
}

Rezultat:

Dzięki selektorowi :after oraz właściwości content:'dodatkowa zawartość' do elementu ul została dodana dodatkowa zawartość w formie dodatkowego elementu HTML tylko do odczytu (nie możemy zaznaczyć jego zawartości oraz jego zawartość nie znajduje się w kodzie części body naszego dokumentu HTML). Domyślnie wspomniany dodatkowy element HTML, którego utworzenie wykonujemy za pomocą selektora :after oraz właściwości content, jest wyświetlony w linii (display:inline;), jednak my potrzebujemy, aby był on elementem wyświetlonym w bloku, dlatego do naszej reguły CSS została dodana właściwość display wraz z wartością block, ponieważ tylko dla elementów blokowych właściwość clear wraz z wartością both sprawia, że nad danym elementem HTML nie może znaleźć się żaden element unoszący się (elementy unoszące się, które występują w kodzie HTML bezpośrednio przed wspomnianym elementem z właściwością clear:both; są wyświetlone przed jego górną granicą). Oczywiście nie chcemy, aby w naszym dodatkowym elemencie HTML, który służy do "naprawy" wysokości elementu ul, znalazł się jakikolwiek tekst, dlatego pozostawiamy go jako element pusty, czyli element bez zawartości (content:'';).

ul:after {
  content:'';
  display:block;
  clear:both;
}

Rezultat:

Podsumowując rozwiązanie naszego problemu zerowej wysokości elementu ul możemy powiedzieć, że od tej pory wysokość elementu ul jest uzależniona od najwyższej wartości wysokości jaką posiadają jego elementy dzieci, czyli elementy li, ponieważ dodatkowy blokowy element HTML, który został dodany do końcowej zawartości elementu ul za pomocą selektora :after oraz właściwości content, wymusza to (za pomocą właściwości clear:both;), aby unoszące się elementy HTML, które występują bezpośrednio przed nim w kodzie danego dokumentu HTML (w naszym przykładzie elementy li wraz z właściwością float) znalazły się nad nim, dzięki czemu stanowi on końcową zawartość elementu ul, dlatego przeglądarka internetowa wyświetla wysokość wspomnianego elementu ul w sposób, w jaki jest bardziej poprawny dla wyglądu naszego poziomego menu CSS.

Wyśrodkowanie poziomego menu CSS

Gdy nasze poziome menu CSS ma zajmować całą szerokość swojego elementu rodzica, nie musimy martwić się o to w jaki sposób możemy wyśrodkować nasze menu CSS, w przeciwnym wypadku musimy wykonać kilka czynności.

Po pierwsze musimy ustalić jakąś wartość szerokości dla głównego elementu HTML, w którym znajdują się elementy naszego poziomego menu CSS, czyli dla elementu ul.

ul {
  width:400px;
  margin:0;
  padding:0;
  list-style-type:none;
  border:1px solid #000;
}

Rezultat:

Po drugie musimy ustawić lewy margines zewnętrzny oraz prawy margines zewnętrzny elementu ul na wartość auto, dzięki czemu przeglądarka internetowa dobierze dla blokowego elementu ul taką samą wartość lewego oraz prawego marginesu zewnętrznego, dlatego wspomniany element ul zostanie wyśrodkowany.

ul {
  width:400px;
  margin:0 auto;
  padding:0;
  list-style-type:none;
  border:1px solid #000;
}

Rezultat:

Szerokość głównych elementów poziomego menu CSS

Elementy li naszego poziomego menu CSS są elementami unoszącymi się, dlatego ich szerokość (jak do tej pory) jest uzależniona od ich zawartości, czyli elementów a oraz tekstu, jaki został umieszczony we wspomnianych elementach a. Zależność tą możemy zmienić, gdy ustalimy wartość szerokości dla poszczególnych elementów li naszego poziomego menu CSS.

Jak do tej pory szerokość elementu ul, w którym znajdują się nasze elementy li, wynosi 400px. Zależy nam na tym, aby unoszące się elementy li pozostały w jednej poziomej linii obok siebie, dlatego suma wartości szerokości wszystkich wspomnianych elementów li nie może przekroczyć wartości szerokości elementu ich rodzica, czyli elementu ul, dlatego wspomnianą wartością jest wartość 400px. Jeżeli wspomniana wartość zostanie przekroczona chociażby o 1px, to naszym oczom ukaże się rezultat, który został zaprezentowany poniżej (ostatni element li zostanie umieszczony w następnej poziomej linii).

Dla naszych elementów li możemy ustalić różne wartości szerokości, jednak muszą one w sumie dać wartość szerokości ich elementu rodzica (element ul), która wynosi 400px, ponieważ tylko wtedy jego cała szerokość zostanie wypełniona elementami li, które są jego dziećmi układającymi się obok siebie. Przykładowo nasze elementy li mogą mieć następujące wartości: 150px, 100px, 150px, bo ich suma wynosi 400px (150px + 100px + 150px = 400px).

/* pierwszy element - li */
ul > li:first-child {
  width:150px;
}

/* drugi element - li */
ul > li:first-child + li {
  width:100px;
}

/* trzeci element - li */
ul > li:first-child + li + li {
  width:150px;
}

Uwaga Omówienie poszczególnych selektorów zaprezentowanych powyżej zostanie przedstawione w następnej części tego działu kursu CSS.

Rezultat:

Od tej pory nasze poziome menu CSS jest wyśrodkowane oraz jego elementy li są wyświetlone obok siebie oraz zajmują (w sumie) dokładnie całą szerokość swojego elementu rodzica, czyli elementu ul. Gdy zmienimy wartość szerokości wspomnianego elementu ul to będziemy musieli również na nowo obliczyć wartość szerokości poszczególnych elementów li. Na przykład, gdy zmienimy wartość szerokości elementu ul z wartości 400px na 350px, to naszym oczom ukaże się efekt, który został zaprezentowany poniżej (suma wartości szerokości wszystkich elementów li będzie za duża, dlatego ostatni element li został umieszczony poniżej pozostałych elementów li).

Aby zabezpieczyć się przed tego typu sytuacją (gdy musimy obliczać ponowną wartość szerokości poszczególnych elementów li) możemy skorzystać z wartości procentowych, za pomocą których ustalamy wartość szerokości dla poszczególnych elementów li (tak, aby w sumie wartości ich szerokości dały wartość 100%, ponieważ wartość szerokości elementu blokowego HTML (ustalona w procentach) jest liczona względem szerokości jego elementu rodzica). Przykładowo nasze elementy li mogą mieć następujące wartości: 30%, 40%, 30%, bo ich suma wynosi 100% (30% + 40% + 30% = 100%).

Uwaga Gdy chcemy, aby nasze trzy elementy li posiadały tą samą wartość szerokości wyrażoną w procentach, to ustalamy dla nich wartość 33.3333% (wartość z czterema miejscami po przecinku), ponieważ w przypadku ustalenia dla każdego elementu li wartości 33%, pozostaje nam dodatkowy 1%, który będzie brakował do wypełnienia całej szerokości elementu ul elementami li (w przypadku ustalenia wartości 33.3333%, dla każdego elementu li, brakującą wartością jest wartość 0.0001%, która jednak nie jest zauważalna dla naszego wzroku, gdy szerokość elementów li ukaże się na naszym ekranie).

Więcej o wartościach procentowych mogliśmy dowiedzieć się z działu pierwszego - Wartości wyrażone w procentach.

/* pierwszy element - li */
ul > li:first-child {
  width:30%;
}

/* drugi element - li */
ul > li:first-child + li {
  width:40%;
}

/* trzeci element - li */
ul > li:first-child + li + li {
  width:30%;
}

Rezultat:

Od tej pory, gdy zmienimy wartość szerokości elementu ul (możemy ją również ustalić w procentach) to nie musimy ustalać na nowo wartości szerokości poszczególnych elementów li naszego poziomego menu CSS.

ul {
  width:80%;
  margin:0 auto;
  padding:0;
  list-style-type:none;
  border:1px solid #000;
}

Rezultat:

Uwaga Do elementów li nie dodajemy (po lewej bądź prawej stronie) takich właściwości jak: margin, padding, border, ponieważ powiększają one całkowitą wartość szerokości danego elementu HTML (przez co suma wartości wszystkich szerokości elementów li będzie większa niż 100%), o czym była mowa w dziale pierwszym - Właściwości CSS zmieniające rozmiar elementu HTML (wspomniane wartości możemy dodać natomiast do elementów, które znajdują się w zawartości poszczególnych elementów li, czyli w naszym przykładzie do elementów a).

ul > li > a {
  display:block;
  margin:15px;
  padding:15px;
  border:3px dashed #F00;
  background-color:#FFF;
  text-decoration:none;
  color:#000;
}

Rezultat:

Wysokość głównych elementów poziomego menu CSS

Jednym z kolejnych problemów, które pojawiają się podczas tworzenia poziomego menu CSS jest problem nierównej wysokości elementów li oraz a w sytuacji, gdy elementy a zawierają różną ilość zawartości, która jest wyświetlona w różnej liczbie wierszy.

Przykład:

W przykładzie zaprezentowanym powyżej drugi element a posiada zawartość wyświetloną w jednej linii natomiast zawartość pierwszego oraz trzeciego elementu a jest wyświetlona w dwóch liniach, dlatego wysokość drugiego elementu a (a co za tym idzie również jego elementu rodzica li) jest różna od pozostałych.

Opisany problem możemy rozwiązać poprzez ustalenie jednakowej wysokości dla wszystkich elementów a naszego poziomego menu CSS.

ul > li > a {
  display:block;
  height:60px;
  margin:15px;
  padding:15px;
  border:3px dashed #F00;
  background-color:#FFF;
  text-decoration:none;
  color:#000;
}

Rezultat:

Co prawda problem nierównej wysokości elementów a oraz li został rozwiązany, lecz zawartość tekstowa elementów a nie jest wyświetlona na równej wysokości w pionie (a o taki efekt najczęściej nam chodzi podczas tworzenia poziomego menu CSS).

Nasz problem nierównej wysokości elementów a oraz li możemy rozwiązać w nieco inny sposób, a mianowicie za pomocą właściwości line-height, która określa wysokość wierszy w danym elemencie HTML. Skoro zawartość pierwszego i drugiego elementu a znajduje się w dwóch wierszach to przykładowo określamy dla tych elementów właściwość line-height wraz z wartością 30px (skoro dwa wiersze to dany element HTML będzie miał w sumie wysokość 60px), natomiast jeżeli zawartość drugiego elementu a znajduje się w jednym wierszu, a wysokość pozostałych elementów a w naszym poziomym menu CSS wynosi 60px, to dla wspomnianego drugiego elementu a określamy wysokość wiersza równą 60px (line-height:60px;).

/* pierwszy element - a */
ul > li:first-child > a {
  line-height:30px;
}

/* drugi element - a */
ul > li:first-child + li > a {
  line-height:60px;
}

/* trzeci element - a */
ul > li:first-child + li + li > a {
  line-height:30px;
}

Rezultat:

Z reguły problem różnej wysokości elementów poziomego menu CSS nie występuje, bo menu tego typu są tworzone dla określonej, jednej szerokości (i z reguły staramy się, aby zawartość ich elementów a znajdowała się w jednym wierszu), lecz jeżeli chcemy, aby nasze manu było bardziej elastyczne musimy tworzyć dodatkowe reguły CSS dla jego poszczególnych elementów HTML. W tym momencie może przydać się nam również wiedza o CSS3 - @media queries.

Podsumowanie

W tej części kursu CSS zostały zaprezentowane poszczególne problemy (głównie ze względu na właściwość float) na jakie możemy napotkać podczas rozpoczęcia budowy naszego poziomego menu CSS. Wiedza ta przyda się nam w następnej części tego działu kursu CSS.