Dzisiaj w Kuchni kodera przepis na wielopoziomowe menu oparte na dwóch składnikach głównych – HTML i CSS, ze szczyptą JS, ale tylko dla smaku. Wiadomo – Javascript tuczy kilobajtami, co gorsze – może zepsuć smak strony szczególnie, jeśli rozmawiamy o nawigacji. Dlatego w dzisiejszym odcinku pokażę, jak ugotować wielopoziomowe menu, w którym JS będzie tylko przyprawą. Ważne! Jeśli nie masz w domu nawet grama JS nie przejmuj się – menu będzie elegancko działać również bez niego.

Pierwszy składnik – HTML

Jak wiadomo wszem wobec, nawigację tworzymy na listach, z wykorzystaniem znaczników listy <ul> oraz elementów listy <li>. Zacznijmy zatem od stworzenia prostego, poziomego menu z kilkoma pozycjami i kilkoma poziomami.

<ul class="menu-lvl-1">
    <li class="lvl-1"><a href="" title="">Home</a></li>
    <li class="lvl-1">
    	<a href="" title="">Oferta</a>
    	<ul class="menu-lvl-2">
            <li class="lvl-2"><a href="" title="">Administracja stronami</a></li>
            <li class="lvl-2">
            	<a href="" title="">Gotowe szablony </a>
               <ul class="menu-lvl-3">
                	<li class="lvl-3"><a href="" title="">Drupal</a></li>
					<li class="lvl-3"><a href="" title="">Joomla</a></li>
					<li class="lvl-3"><a href="" title="">WordPress</a></li>
                </ul>
            </li>
            <li class="lvl-2"><a href="" title="">Projekty graficzne</a></li>
            <li class="lvl-2"><a href="" title="">Cięcie i kodowanie</a></li>
            <li class="lvl-2"><a href="" title="">Audyty stron www</a></li>
            <li class="lvl-2"><a href="" title="">Inne</a></li>
        </ul>
    </li>
    <li class="lvl-1"><a href="" title="">O nas</a></li>
    <li class="lvl-1"><a href="" title="">Realizacje</a></li>
    <li class="lvl-1"><a href="" title="">Kontakt</a></li>
</ul>

Kod HTML nie wymaga jakiegoś szczególnie długiego komentarza – tak myślę. Generalnie wielopoziomowe menu istnieje już na tym etapie, przy czym brak mu podstawowej i charakterystycznej dla wielopoziomowego menu funkcjonalności. Tak więc mamy poziom pierwszy z listą o klasie .menu-lvl-1 i elementami listy o klasach .lvl-1. Kolejny poziom przyporządkowany został do elementu Oferta – jest to lista o klasie .menu-lvl-2 i elementami listy o klasach .lvl-2. Trzeci i jednocześnie ostatni poziom został przyporządkowano do elementu Oferta –> Gotowe szablony w postaci listy o klasie .menu-lvl-3 z elementami listy o klasach .lvl-3.

Myślę, że nie jest to specjalnie skomplikowane – jeśli ktoś ma problem z zajarzeniem, proponuję prześledzić sobie dokładnie powyższy kod. Dodam od razu, że przyjąłem założenie, że menu będzie miało trzy poziomy, ponieważ uważam, że większa ilość to już pogorszenie funkcjonalności strony. Jeśli ktoś uważa inaczej, to pod koniec wpisu, na zasadzi analogii, powinien być w stanie stworzyć kolejne poziomy bez mojej pomocy.

Drugi składnik – CSS

Tu będzie trochę więcej czytania – uprzedzam na wstępie. Przede wszystkim muszę zaznaczyć, że nie wszystkie właściwości są niezbędne do działania menu – część z nich ma charakter czysto dekoracyjny. W miarę możliwości postaram się wskazywać te właściwości, które sa niezbędne do prawidłowego funkcjonowania menu.

Zacznijmy od określenia najbardziej zewnętrznej puli właściwości:

a {
	font:11px Arial, Helvetica, sans-serif;
	color:#fff;
	text-decoration:none;
	line-height:1.3em;
	display:block;
	background:#333;
	padding:7px 15px;
	margin:0 1px 0 0;
}

ul {
	list-style:none;
	margin:0;
	padding:0;
}

Praktycznie wszystkie powyższe właściwości mają charakter dekoracyjny, poza jedną – display:block dla znaczników <a>, dzięki której będą one wyświetlane jak elementy blokowe, a nie liniowe (bo tak jest domyślnie). Na tym etapie wygląd menu zmienił się niewiele.

W następnym kroku zajmijmy się wyglądem pierwszego poziomu:

.menu-lvl-1 {}

.lvl-1 {
	position:relative;
	float:left;
}

.lvl-1:hover a {
	text-decoration:underline;
	color:#fff;
	background:#c11;
}

Właściwości, bez których nie obędziemy się na dalszym etapie znajdują się miedzy wąsami klasy .lvl-1 – to position:relative oraz float:left. Pierwsza – najistotniejsza – pozwoli utrzymać w ryzach kolejny poziom, który będziemy pozycjonować absolutnie, druga – sprawi, że menu będzie wyświetlać się w poziomie. Jeszcze odnośnie pierwszej właściwości – jeśli nie rozumiecie, czemu jest ona tak istotna i jaki ma związek z pozycjonowaniem absolutnym kolejnych elementów, odsyłam pod ten adres. Niestety po angielsku.

Jak widać nasze menu zaczyna nabierać kształtów. Wygląda już w miarę sensownie, niestety – wszystkie inne poziomy są widoczne, dlatego w następnym kroku ukryjemy je:

.menu-lvl-2 {
	position:absolute;
	width:150px;
	display:none;
	background:url(../);
}

.lvl-2 {
	position:relative;
	margin-top:1px;
}

Nadając liście .menu-lvl-2 właściwość display:none ukryliśmy ją, a w raz z nią wszystkie niższe poziomy menu, dlatego poza pierwszym poziomem, żaden inny nie będzie widoczny. Za chwilę zmienimy to w ten sposób, żeby pozostałe poziomy wyświetlały się po najechaniu myszą na elementy listy o klasie .lvl-1, ale na razie skupmy się na pozostałych właściwościach. Właściwość position:absolute sprawi, że kolejny poziom będzie pozycjonował absolutnie, ale nie względem <body>, tylko względem elementu listy .lvl-1, ponieważ element ten ma ustawioną właściwość position:relative;. Jedną z zalet tego rozwiązania jest to, że szerokość listy .menu-lvl-2, którą tak przy okazji ustawiliśmy na 150px, nie będzie wpływać na szerokość rodzica. Przekonajcie się sami usuwając z kody pozycjonowanie absolutne dla tego elementu.

Po raz kolejny uczulam na właściwość position:relative; dla elementów listy .lvl-2 – bez niej sensowne budowanie kolejnych poziomów będzie niemożliwe.

Być może zastanawiacie się, do czego służy zapis background:url(../);? Otóż jest to taki mały, niecny hack dedykowany przeglądarce IE. Bez niego menu nie będzie działać poprawnie w wersji 7. W IE 8 będzie śmigać bez problemu. Jeśli chcecie się o tym przekonać sami, a macie zainstalowaną tylko wersje 8 Explorera, dodajcie w sekcji <heade> takie coś:

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"/>

a następnie usuńcie rzeczony zapis i odpalcie menu w Internet Explorerze.

Pora zadbać o to, żeby kolejny poziom menu wyświetlał się po najechaniu myszą na odpowiedni element listy. Ten efekt osiągniemy stosując pseudoklasę :hover dla elementów listy .lvl-1:

.lvl-1:hover .menu-lvl-2 {
	display:block;
}

Powyższy zapis należy interpretować w następujący sposób – jeśli kursor myszy znajduje się nad elementem .lvl-1, to liście .menu-lvl-2 nadaj właściwość display:block;, innymi słowy – pokaż ją. Tak też interpretują go przeglądarki, wiec jeśli teraz najedziesz kursorem na Ofertę, wyświetlą się kolejne poziomy menu.

Oczywiście to wciąż nie jest to, o co nam chodziło – w końcu nie chcemy, żeby tak od razu wyświetlały się wszystkie poziomy, tylko poziom drugi. W nastepnym kroku ukryjmy więc kolejne poziomy i udekorujmy nieco przyciski poziomu drugiego:

.lvl-1:hover .lvl-2 a {
	color:#fff;
	text-decoration:none;
	background:#333;
}

.lvl-1:hover .lvl-2 a:hover {
	text-decoration:underline;
	color:#fff;
	background:#c11 ;
}

.lvl-1:hover .lvl-2:hover a {
	text-decoration:underline;
	color:#fff;
	background:#c11 ;
}

.menu-lvl-3 {
	position:absolute;
	left:100%;
	top:0;
	@top:3px;
	display:none;
}

Przyjrzyjmy się temu, co zrobiliśmy:

  • Pierwszy zapis określa wygląd elementu <a> listy .menu-lvl-2, kiedy kursor znajduje się nad elementem listy .lvl-1
  • Drugi zapis określa wygląd elementu <a> listy .menu-lvl-2, kiedy kursor znajduje się nad tymże elementem – określamy zatem właściwości linku po najechaniu na niego (na pewno robiliście to setki razy)
  • Trzeci zapis określa wygląd elementu <a> listy .menu-lvl-2, kiedy kursor znajduje się nad ta listą, ale nie nad tym elementem <a> (w praktyce – kiedy rozwinie się trzeci poziom)

Ostatni zapis, już nie dekoracyjny, określa właściwości trzeciego poziomu menu, czyli trzeciej listy o klasie .menu-lvl-3. Podobnie jak w przypadku .menu-lvl-2, ukrywamy te listę właściwością display:none; i pozycjonujemy ją absolutnie względem elementu .lvl-2. Tym razem zmieniamy także jej położenie – nie chcemy, żeby lista wyświetlała się pod spodem elementu .lvl-2 (mało praktyczne rozwiązanie), tylko z boku, dlatego określamy jej położenie na left:100%; i top:0;. Dodatkowo specjalnie dla IE7 zastosujemy zapis @top:3px;. Małpka przed właściwością spowoduje, że będzie ona widoczna tylko dla IE7<=7.

Nasze wielopoziomowe menu jest już prawie gotowe. Pozostało określić pseudoklasę :hover dla elementu .lvl-2 oraz wygląd przycisków w rożnych stanach upojenia kursorowego:

.lvl-2:hover .menu-lvl-3 {
	display:block;
}

.lvl-3 {
	margin-bottom:1px;
}

.lvl-1:hover .lvl-2:hover .lvl-3 a {
	text-decoration:none;
	color:#fff;
	background:#333;
}

.lvl-1:hover .lvl-2:hover .lvl-3 a:hover {
	text-decoration:underline;
	color:#fff;
	background:#c11;
}

Przede wszystkim określamy pseudoklasę :hover elementu .menu-lvl-3 zmieniając właściwość display:none na display:block po najechaniu na kursorem na element listy .lvl-2. Następnie określamy właściwości elementy listy .lvl-3. których jak widać nie ma zbyt wielu, a na koniec definiujemy poszczególne stany dla elementu <a> listy .menu-lvl-3.

Wielopoziomowe menu jest już w zasadzie gotowe. W całości możecie je sobie obejrzeć tutaj. Powinno działać bez problemu w FF 3.6.12, IE 7-8, Operze 10.6 oraz Chromie 7. Nie wiem jak z innymi przeglądarami, ale powinno być ok. Jeśli zauważycie jakieś błędy albo bugi - piszcie.

Trzeci składnik - JavaScript

Ostatni składnik nie jest nam w ogóle do szczęścia potrzebny, ale na pewno poprawi nam humor i wygląd naszego menu. Zacznijmy od tego, że posłużymy się biblioteką jQuery, tak więc koniecznie musicie w nagłówku umieścić odniesieni do tej biblioteki:

<script src="http://code.jquery.com/jquery-1.4.4.min.js" type="text/javascript"></script>

W kolejnym kroku usuniemy te fragmenty CSS, które odpowiadają za ukrywanie poszczególnych poziomów. Żeby jednak menu było w pełni funkcjonalne i działało również przy wyłączonej obsłudze JavaScript, przesuniemy dwa zapisy do znacznika <noscript>:

<noscript>
<style type="text/css">
.lvl-1:hover .menu-lvl-2 {
	display:block;
}
.lvl-2:hover .menu-lvl-3 {
	display:block;
}

</style>
</noscript>

Tuż przed zamknięciem znacznika <body> stworzymy sobie malutką JavaScriptową funkcję, która będzie elegancko animować nasze menu:

<script type="text/javascript">
$(function(){
	function showIt(liClass){
		$(liClass).hover(
			function() {
				$('ul',this).first().slideDown()
			},
			function() {
				$('ul',this).first().slideUp()
			}
		)
	}

	showIt('.lvl-1')
	showIt('.lvl-2')
})
</script>

Jeśli chodzi o działanie funkcji, to osoby zaznajomione z jQuery nie powinny miec problemu z jej odszyfrowaniem, natomiast osoby niezaznajomione odsyłam do dokumentacji. Ten drobny skrypcik sprawi, że menu będzie się ładnie animować. Oczywiście efekt możemy zmieniać wedle uznania.

That's it! Menu jest gotowe!.

Podobne wpisy: