Uwaga! Trwają prace nad nową wersją serwisu. Mogą występować przejściowe problemy z jego funkcjonowaniem. Przepraszam za niedogodności!
⛔ Potrzebujesz wsparcia? Oceny CV? A może Code Review? ✅ Dołącz do naszej społeczności na Discordzie!
Jak stworzyć menu na stronę jedynie za pomocą HTML-a i CSS-a? Poziom artykułu zakłada, że znasz już podstawy obu tych technologii. W treści skupimy się na odpowiednim ustawieniu elementów menu względem siebie, ukrywaniu i odkrywaniu drop-downów zależnie od pozycji kursora oraz na zmianie tła elementów menu po najechaniu na nie myszą.
Chcesz lepiej zapamiętać to zagadnienie? Wykonaj warsztat z HTML i CSS: Podstawy, aby osiągnąć swój cel!
Zanim przejdziemy do rzeczy, upewnijmy się, że mówimy o tym samym. Na poniższej grafice widzisz menu trzypoziomowe z dwoma drop-downami:
Drop-down to okienko pojawiające się po (zależnie od implementacji) kliknięciu lub najechaniu na element menu, a poziom to każda z „sekcji” menu. W naszym przypadku pierwszy poziom jest bezpośrednio widoczny dla użytkownika w postaci górnego paska. Drugi poziom pojawia się po najechaniu kursorem na pozycję „Oferta”, a trzeci poziom – po najechaniu na pozycję „Kursy wideo”.
Zrozumienie tego pomoże nam zaplanować strukturę HTML.
Jeszcze mała uwaga do urządzeń mobilnych: tam hover (najechanie na element) zostanie aktywowany po tapnięciu. Nie ma wskaźnika, który mógłby przesuwać się ponad elementem, jak na przykład na desktopie robi to kursor.
Zacznijmy od stworzenia pierwszego poziomu menu:
<nav> <ul> <li><a href="#home">Strona główna</a></li> <li><a href="#offer">Oferta</a></li> // tu docelowo będzie drop-down <li><a href="#contact">Kontakt</a></li> </ul> </nav>
Później dodamy do tych elementów odpowiednie klasy, które pomogą nam w stylowaniu, lecz na razie chcę, aby struktura menu była dla Ciebie jak najbardziej przejrzysta.
Pierwszy poziom nie stanowi problemu. Element nav semantycznie pasuje do nawigacji, za którą przecież odpowiada menu, a lista nieuporządkowana ul ma w sobie jedynie dzieci, które zgodnie z dokumentacją może zawierać. Przykładowo na MDN w podpunkcie Permitted content przeczytamy: Zero or more <li>, <script> and <template> elements.
Co to oznacza? Oznacza to, że nie powinniśmy umieszczać wewnątrz ul np. linków w taki sposób:
<ul> <a href="#"><li>Strona główna</li></a> <a href="#offer"><li>Oferta</li></a> <a href="#contact"><li>Kontakt</li></a> </ul>
Nieprawidłowa semantycznie struktura może osłabiać dostępność naszej strony dla osób korzystających np. z czytników ekranowych czy innych narzędzi analizujących kod HTML. Trzymajmy się więc tego, że linki umieszczamy dopiero wewnątrz elementów li.
Zadajmy sobie tutaj dwa UX-owe pytania:
Na pierwsze pytanie odpowiem sobie „nie” (usunę więc link). Oczywiście zależy to też np. od wymagań klienta, ale z reguły pod względem doświadczenia użytkownika lepiej jest nie umieszczać linku pod pozycją z drop-downem.
Dlaczego? Ponieważ może się zdarzyć taki scenariusz:
Denerwujące 😉
Na drugie pytanie odpowiem sobie tak: za słowem „Oferta” umieszczę strzałkę w dół, by było wiadomo, że kryje się pod nim jakaś lista. Można to zrobić np. z poziomu CSS-a, stylując pseudoelement after. Teraz jednak nie na tym będziemy się skupiać, skrócę więc sobie drogę i użyję symbolu ▼.
Oto nasz drugi poziom:
<nav> <ul> <li><a href="#home">Strona główna</a></li> <li>Oferta ▼ <ul> <li><a href="#shop">Sklep</a></li> <li><a href="#courses">Kursy wideo</a></li> </ul> </li> <li><a href="#contact">Kontakt</a></li> </ul> </nav>
Zasady są dwie:
1. Nową listę tworzymy wewnątrz elementu li należącego do menu wyższego poziomu (zwróć uwagę, czy masz tag zamykający </li>!),
<li>Oferta ▼ <ul> <li><a href="#shop">Sklep</a></li> <li><a href="#courses">Kursy wideo</a></li> </ul> </li>
2. Nowy poziom menu powinien być listą, czyli np. elementem ul (to raczej najczęstsza opcja), ol czy menu – będzie to poprawne pod względem semantyki.
Pomyślisz: OK, a co, jeśli ja chcę mieć podlinkowaną „Ofertę”, lecz jednocześnie umieścić pod nią drop-down? Wówczas robisz jak poniżej.
<nav> <ul> <li><a href="#home">Strona główna</a></li> <li><a href="#offer">Oferta ▼</a> <ul> <li><a href="#shop">Sklep</a></li> <li><a href="#courses">Kursy wideo</a></li> </ul> </li> <li><a href="#contact">Kontakt</a></li> </ul> </nav>
Pamiętaj, aby umieścić tag zamykający </a> zaraz za nazwą pozycji menu, bo jeśli zrobisz to dopiero na końcu przed tagiem zamykającym </li>, to możesz napotkać spore problemy podczas stylowania!
Trzeci poziom i każdy kolejny tworzymy podobnie: wstawiamy go do elementu li i nie zapominamy zamknąć tagu. Ja zdecydowałam się jeszcze na usunięcie linku spod pozycji „Kursy”.
<nav> <ul> <li><a href="#home">Strona główna</a></li> <li>Oferta ▼ <ul> <li><a href="#shop">Sklep</a></li> <li>Kursy ▶ <ul> <li><a href="/html-css-course">HTML i CSS</a></li> <li><a href="/js-course">JavaScript</a></li> </ul> </li> </ul> </li> <li><a href="#contact">Kontakt</a></li> </ul> </nav>
Jeżeli chcesz zgłębić tworzenie klas zgodnie z metodologią BEM, to zapraszam Cię do artykułu „Metodologia BEM w CSS i Sass”. Tymczasem nasze menu z klasami prezentuje się teraz tak:
<nav class="menu"> <ul class="menu__list"> <li class="menu__item"> <a href="#home" class="menu__link">Strona główna</a> </li> <li class="menu__item menu__item--parent"> Oferta ▼ <ul class="menu__sublist menu__sublist--bottom"> <li class="menu__item"> <a href="#shop" class="menu__link">Sklep</a> </li> <li class="menu__item menu__item--parent"> Kursy wideo ▶ <ul class="menu__sublist menu__sublist--right"> <li class="menu__item"> <a href="/html-css-course" class="menu__link">HTML i CSS</a> </li> <li class="menu__item"> <a href="/js-course" class="menu__link">JavaScript</a> </li> </ul> </li> </ul> </li> <li class="menu__item"> <a href="#contact" class="menu__link">Kontakt</a> </li> </ul> </nav>
Nasze menu ma formę górnego paska na stronie, zatem wystarczy – oprócz nadania koloru czy stylowania fontu – użyć np. flexboxa, by łatwo ustawić elementy obok siebie.
/* Basic style reset */ * { padding: 0; margin: 0; box-sizing: border-box; } ul { list-style: none; } a { text-decoration: none; display: block; } /* Main menu */ .menu { background-color: #3d3aeb; color: #fff; font-family: 'Courier New', Courier, monospace; font-size: 16px; font-weight: bold; white-space: nowrap; } .menu__list { display: flex; } .menu__link, .menu__item--parent { padding: 15px 20px; } .menu__link { color: #fff; } .menu__item--parent { cursor: default; position: relative; }
W powyższym kodzie podświetlono trzy rzeczy:
Teraz przechodzimy do prawidłowego ustawienia drop-downów. Docelowo będą one ukryte (stąd obecna już, ale zakomentowana deklaracja display: none). Do prawidłowego ustawienia list submenu użyjemy pozycjonowania absolutnego.
Rodzic/przodek, względem którego chcemy pozycjonować inny element, sam musi być pozycjonowany (mieć wartość inną niż domyślna static), dlatego element li, pod którym kryje się drop-down ma przypisaną deklarację position: relative (nie wpływa to na jego pozycję, jak np. wartość fixed).
.menu__item--parent { cursor: default; position: relative; } /* Drop-down */ .menu__sublist { display: none; position: absolute; background-color: #3d3aeb; } .menu__sublist--bottom { left: 0; top: 100%; } .menu__sublist--right { left: 100%; top: 0; }
Teraz sublisty mogą otrzymać wartość absolute, co wyrzuci je poza ich dotychczasową pozycję i ustawi względem przodka pozycjonowanego relatywnie.
Aby drop-downy „wskoczyły na miejsce”, trzeba ustawić odpowiednie wartości dla top i left. Wartości te, jeżeli używamy procentów, korzystają z rozmiarów przodka pozycjonowanego relatywnie (dla ułatwienia nazwę go „przodkiem”).
Jeśli zatem drop-down drugiego poziomu ma być bezpośrednio pod elementem „Oferta”, musi być odepchnięty od góry o 100% wysokości przodka. Jeśli drop-down trzeciego poziomu ma wyskakiwać bezpośrednio po prawej od „Kursy wideo”, musi być odepchnięty od lewej krawędzi o 100% szerokości przodka. Wartość 0 będzie oznaczała zrównanie się z daną krawędzią przodka.
Gdy elementy są już prawidłowo ustawione, dodajmy zmianę koloru tła pozycji menu po najechaniu na nie kursorem:
/* Change background color on hover for menu and drop-down items */ .menu__item:hover { background-color: #201dca; }
Czas ukryć nasze drop-downy. Odkomentujmy więc deklarację display: none dla klasy .menu__sublist. Drop-downy zniknęły! Teraz sprawmy, by pokazywały się po najechaniu na odpowiedni element listy.
/* Show drop-down on hover of the parent menu item */ .menu__item--parent:hover > .menu__sublist { display: block; }
Powyższy selektory czytamy tak: po najechaniu na element listy (li) – pod którym kryje się drop-down – dla bezpośredniego dziecka tego elementu, czyli sublisty (ul), ustaw display: block. Spowoduje to pokazanie się drop-downu użytkownikowi.
Jeżeli znasz tego zapisu ze znakiem większości, zapoznasz się z nim na przykład na MDN: Child combinator.
Wiesz już, czym jest menu trzypoziomowe i jaki jest mechanizm pokazywania drop-downów. Spróbuj teraz stworzyć własne menu. Inspirację znajdziesz na przykład na stronach takich jak Dribbble (dla UI/UX designerów i grafików). Kolejnym Twoim krokiem niech będzie sprawienie, by menu dobrze prezentowało się urządzeniach o różnych wielkościach ekranu.
Udostępnij ten artykuł:
Potrzebujesz cotygodniowej dawki motywacji?
Zapisz się i zgarnij za darmo e-book o wartości 39 zł!
PS. Zazwyczaj rozsyłam 1-2 wiadomości na tydzień. Nikomu nie będę udostępniał Twojego adresu email.
Mam coś dla Ciebie!
W każdy piątek rozsyłam motywujący do nauki programowania newsletter!
Dodatkowo od razu otrzymasz ode mnie e-book o wartości 39 zł. To ponad 40 stron konkretów o nauce programowania i pracy w IT.
PS Zazwyczaj wysyłam 1-2 wiadomości na tydzień. Nikomu nie będę udostępniał Twojego adresu e-mail.