Rozklikávací menu v CSS a JavaScriptu

26. června 2008

Nedávno jsem stál před úkolem napsat javascriptový kód pro rozklikávací menu (jednotlivé větve navigace se zobrazují a schovávají po kliknutí myší, tedy z pohledu JavaScriptu při události „onclick“). Všechna řešení, která lze obvykle na internetu najít, však byla příliš komplikovaná nebo nevyhovovala technicky. Nakonec jsem si navrhl vlastní řešení, které se mi osvědčilo a se kterým bych vás proto chtěl seznámit.

V rozklikávacím menu je první otázkou, který element při kliknutí zareaguje – častým řešením je odchytit kliknutí na odkazu, tedy značce a, což ovšem znamená, že nemůže fungovat jako odkaz na stránku představující danou kategorii. Některé varianty rozklikávacího menu (v angličině většinou expanding and collapsing menu nebo accordion menu) používají jako tento aktivní element dokonce značku img, která ovšem narušuje čistotu HTML kódu. Další varianty zase používají příliš rozsáhlý JavaScript (a to úplně pomíjím verze, kdy se celá struktura navigace generuje JavaScriptem).

Základní myšlenka mého řešení je jednoduchá – ostylovat menu tak, aby z každé značky li byl vidět jen levý horní roh, a odchytávat událost onclick právě na této značce. Při kliknutí se změní styl (class v HTML, čili className v JavaScriptu) tak, aby podmenu (značka ul obsažená v li) jednou byla vidět a jednou ne. Pokud chcete do menu doplnit grafiku (rozklikávací tlačítka ve stylu Průzkumníka Windows a podobných), nastavíte je v závěru v CSS jako background-image právě pro li.

Východiskem v HTML je samozřejmě neuspořádaný seznam ul, který obsahuje jednotlivé položky li a ty následně další seznam ul nebo přímo odkaz a. Pro názornost jsem nejdřív vytvořil menu bez obrázků, v němž jsou barevně odlišené jednotlivé značky. Následující obrázek ukazuje, jak by (částečně rozbalené) menu mělo vypadat ve vašem prohlížeči, otestovat si to můžete v živé ukázce.

Oranžové pozadí mají odkazy a, které jsou přestylovány na blokové elementy, aby vyplnily celou šířku nadřazeného li s výjimkou malé části vlevo (to zajistí margin-left u odkazu). Tam je vidět pozadí li – šedé pro normální položky, červené pro položky se sbaleným podmenu (class „s“) a zelené pro položky s rozbaleným podmenu (class „r“). Konečně různými odstíny modré je zvýrazněné pozadí bloků ul v různých úrovních (ty mají od druhé úrovně nastavený levý padding).

Upravit toto rozklikávací menu tak, aby se v něm objevily obrázky, je prosté, stačí je nastavit jako background-image pro class „r“ a „s“ značek li, a to do vykukujícího levého rohu (viz další ukázka).

Ladění pro IE

V barevně kódovaném výpisu použitých kaskádových stylů je černou barvou označen kód, který tvoří konkrétní grafický vzhled menu, ale není pro jeho funkčnost důležitý, a červeně kód, který je podstatný z hlediska funkčnosti. Modrou barvou je zvýrazněn kód, který je nezbytný pro správnou funkčnost v Internet Exloreru (pro lepší správu v produkčním prostředí je vhodné ho vyčlenit do samostatného souboru a připojit prostřednictvím podmíněných komentářů).

Větší část speciálního stylu pro IE má za cíl odstranit problémy s nadbytečnými mezerami pod položkami uspořádaného seznamu, takzvaný whitespace bug. Problém je v tom, že pokud jednotlivým li nastavíme display: block, pak se mezi položkami menu objeví mezery na výšku jednoho řádku, což samozřejmě nemůžeme potřebovat (předpokladem funckčnosti našeho řešení je to, že elementy a a ul vyplní nadřazené li beze zbytku, s výjimkou levého horního rohu).

Léčbou na tento neduh je nucené zapnutí vlastnosti hasLayout pro odkazy, což lze udělat různým způsobem. Jednou možností je použití CSS vlastnosti zoom, což je ovšem nestandardní rozšíření IE. V našem případě použijeme řešení Rogera Johanssona, kdy se nejprve v jednom pravidlu zapne hasLayout nastavením display: inline-block a v dalším pravidlu se předefinuje zpět na display: block. I po tomto zákroku však pod položkami menu zůstanou tenké mezírky, které je však možné eliminovat například nastavením font-size pro značku body.

Konečně poslední úlitbou Internet Exploreru je vynucení hasLayout pro značky li – bez toho jednotlivé položky v JavaScriptu nereagují na událost onclick, jejmž zdrojovým elementem kupodivu pořád zůstává jen nadřazená značka ul představující celé menu.

JavaScript

Na JavaScript už příliš práce nezbývá. Událost onclick je registrovaná na celém menu a zpracování se provádí jen pokud je zdrojový element (vlastnost target objektu event ve standardních prohlížečích a srcElement v IE) li s class „r“ nebo „s“. V tom případě se className zdrojového elementu změní na opačný.

Zdrojový kód je tedy velmi krátký:

function menu_prepnout(e) {
   var zdroj,trida;
   e = e || window.event;
   zdroj = e.target || e.srcElement;
   trida = zdroj.className;
   if (zdroj.nodeName.toLowerCase()==“li“ && (trida==“s“ || trida==“r“)) {
      zdroj.className = (trida==“r“) ? „s“ : „r“;
   }
   }
   
var menu = document.getElementById(„menu“);
menu.onclick = menu_prepnout;

Odkazy a zdroje

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Štítky: Články

Mohlo by vás také zajímat

Nejnovější

2 komentářů

  1. Beny

    Čvn 16, 2010 v 20:50

    Moc v JS neumím, muzete me nekdo poradit jak se zbavit toho, ze kdyz kliknu na polozku tak se menu zase zavre…. Potreboval bych aby pri kliknuti zustalo menu porad otevrene.. Za vecnou odpoved diky:)

    Odpovědět
  2. Petrik

    Led 12, 2011 v 14:43

    Dobrý den

    Chci se zeptat jak nastavit JS nebo CSS tak aby se menu otevřelo při kliknutí na nápis za li a ne na značku li (třeba aby se Alexandrie, Asuan a Káhira otevřela při kliknutí na Egypt). A také mě zajímá jak nastavit JS tak jak to myslel Beny. Také moc s JS neumím. Předem děkuji za odpověď.

    Odpovědět

Napsat komentář: Petrik Zrušit odpověď na komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *