Rozklikávací menu v CSS a JavaScriptu
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
- Jedno z řešení whitespace bugu
- Koncept hasLayout na stránkách Microsoftu (podrobnější rozbor od Markuse Mielkeho)
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Nové AI modely od Open AI a Google
22. května 2024 -
Gaming na HDR monitoru: Stojí to za to?
12. srpna 2024
Nejnovější
-
Výkonný a kompaktní: ASOME Max Studio s výjimečným poměrem cena/výkon
11. listopadu 2024 -
Šokující data od Microsoftu: Kyberútoky rostou o stovky procent!
8. listopadu 2024 -
Chcete jedinečnou doménu? Objevte koncovky FOOD, MEME a MUSIC!
7. listopadu 2024 -
OpenAI představilo novou funkci ChatGPT Search
6. listopadu 2024
Beny
Čvn 16, 2010 v 20:50Moc 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:)
Petrik
Led 12, 2011 v 14:43Dobrý 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ěď.