Rozwijane menu (Suckerfish Dropdowns)
Niniejszy tekst powstał w oparciu o artykuł na stronie A List Apart i nie jest jego tłumaczeniem w ścisłym sensie. Autorami oryginalnego rozwiązania „Suckerfish Dropdowns” są Patrick Griffiths i Dan Webb. Pozwoliłem sobie wprowadzić drobne modyfikacje do tłumaczenia jak również wzbogacić opis o okienka z podglądem aktualnie omawianego kodu.
Pragnę zaznaczyć, że jest to wersja robocza, która ostatecznie będzie uwzględniała zmiany polityki tworzenia stron (ukrywanie elementów strony przez display: none może uniemożliwić jej odbiór przez osoby korzystające z programów czytających) oraz poprawki przedstawione przez autorów rozwiązania na stronie Son of Suckerfish Dropdowns.
Wszelkie uwagi dotyczące tego artykułu, jak również propozycje lepszego przetłumaczenia pewnych trudnych zwrotów z języka angielskiego (np. „floating elements to the left”) są oczywiście mile widziane. Proszę o umieszczenie komentarza na moim blogu pod informacją o tym artykule lub skontaktowanie się poprzez Jabbera (JID tamże).
Ostatnia aktualizacja: 17 lipca 2005 o godz. 13:07.
Obecne techniki tworzenia rozwijanych menu stosują ogromne ilości kodu JavaScript w połączeniu z mało czytelnymi i często niezgodnymi z jakimikolwiek standardami konstrukcjami w HTML. Menu te najczęściej niewiele mają wspólnego z semantycznością a jeszcze mniej z dostępnością. Do tego w większości przypadków mają problemy z działaniem pod nowoczesnymi przeglądarkami. Niejeden twórca stron internetowych marzył o uniwersalnym rozwiązaniu pozbawionym wymienionych wad a do tego łatwego w zaimplementowaniu w dowolnym projekcie.
I oto jest! Lekkie, dostępne, zgodne ze standardami, dla każdej przeglądarki. Rozwijane menu oparte o CSS.
Konstrukcja kodu
- Paleozoik
- Mezozoik
- Kenozoik
Na początek skorzystamy z najlepszej metody tworzenia menu nawigacyjnego, które w istocie jest listą. Na potrzeby tego opisu użyjemy listy nieuporządkowanej.
<ul>
<li>Paleozoik
<ul>
<li><a href=”#”>Kambr</a></li>
<li><a href=”#”>Ordowik</a></li>
<li><a href=”#”>Sylur</a></li>
<li><a href=”#”>Dewon</a></li>
<li><a href=”#”>Karbon</a></li>
<li><a href=”#”>Perm</a></li>
</ul>
</li>
<li>Mezozoik
<ul>
<li><a href=”#”>Trias</a></li>
<li><a href=”#”>Jura</a></li>
<li><a href=”#”>Kreda</a></li>
</ul>
</li>
<li>Kenozoik
<ul>
<li><a href=”#”>Paleogen</a></li>
<li><a href=”#”>Neogen</a></li>
</ul>
</li>
</ul>
Jak dotąd całkiem sympatycznie – zgrabny i czytelny HTML. Na dodatek spełniający wymogi dostępności. Zajmiemy się teraz jego transformacją w dynamiczną listę – pierwszy poziom listy będzie stanowił poziomą listwę menu zaś listy drugiego poziomu będą rozwijane.
Stylowanie
- Paleozoik
- Mezozoik
- Kenozoik
Najpierw musimy zrobić mały porządek z listami, a dokładnie wyzerować margines (margin) i odstęp wewnętrzny (padding) oraz styl listy (list-style) ustawić na none:
ul {
padding: 0;
margin: 0;
list-style: none;
}
- Paleozoik
- Mezozoik
- Kenozoik
Następnie zmienimy pierwszy poziom listy w poziomy pasek menu. Jest na to wiele sposobów, które opisane są w innym miejscu. Możemy na przykład wyświetlić elementy listy w jednej lini (display: inline), ale w tym przykładzie nadamy im float: left:
li {
float: left;
position: relative;
width: 10em;
}
Pozycja musi zostać ustawiona na relative, ponieważ chcemy aby listy drugiego, zagnieżdżonego poziomu były pozycjonowane względem elementów z poziomu pierwszego. Szerokość wykorzystamy aby dodać nieco odstępu pomiędzy poszczególnymi pozycjami. Menu zaczyna przypominać rozwijane.
- Paleozoik
- Mezozoik
- Kenozoik
Następnym krokiem będzie dopracowanie list drugiego poziomu, które będą właściwym menu rozwijanym:
li ul {
display: none;
position: absolute;
top: 1em;
left: 0;
}
Dzięki temu drugi poziom zostanie wypozycjonowany absolutnie (niejako „wyciągając” go ze struktury dokumentu HTML do własnego świata) oraz przestanie być widoczny. Jeśli zamienisz display: none na display: block zrozumiesz potrzebę ustawienia parametrów top i left w przeglądarce Internet Explorer, ponieważ bez nich IE ustawi drugi poziom w górnym prawym rogu nadrzędnego elementu zamiast w dolnym lewym. Niestety ta poprawka popsuje wyświetlanie w przeglądarkach takich jak Opera, więc należy dodać następujący fragment kodu CSS, który przywróci prawidłowe parametry top i left w przeglądarkach innych niż IE:
ul > li {
top: auto;
left: auto;
}
- Paleozoik
- Mezozoik
- Kenozoik
A teraz uruchomimy nasze rozwijane menu. Aby pokazać listy drugiego poziomu po wskazaniu kursorem myszy elementu rodzica po prostu musimy dodać ten fragment:
li:hover ul{ display: block; }
Co oznacza, że każda lista, która znajduje się we wskazanym kursorem elemencie innej listy powinna być wyświetlona.
Na koniec, ponieważ listy mają ustawiony parametr float: left, należy dla reszty zawartości mającej znajdować się poniżej ustawić parametr clear: left, dzięki któremu wyświetli się on pod paskiem menu, a nie obok.
Zaraz! Chwila!
„To durne rozwijane menu nie działa!” - słychać płacz 80% (czy ile tam teraz aktualnie jest) osób. Jak łatwo się domyślić, chodzi tu o użytkowników programu Internet Explorer. Im częściej używasz i projektujesz w przeglądarkach takich jak Firefox tym bardziej dostrzegasz jak dramatycznie wygląda Internet Explorer w kwestii obsługi standardów. Pseudoklasa :hover powinna działać z każdym elementem, ale w IE działa tylko z odnośnikami. Jaki jest więc pożytek z menu, które działa pod ~20% przeglądarek? Szczerze mówiąc niezbyt duży. Przyszedł czas na trochę magii.
Z odsieczą: Skrypt oparty na DOM
Ustaliliśmy, że IE kuleje przy obsłudze pseudoklasy :hover jednak wykorzystując Obiektowy Model Dokumentu (DOM) możemy podłączyć obsługę zdarzeń onmousover i onmouseout do każdego elementu. To dla nas dobra wiadomość, bo przy użyciu strzępka kodu JavaScript możemy pozbyć się problemów z :hover pod IE.
Ponieważ IE jest ślepy, musimy znaleźć inny sposób na zastosowanie pseudoklasy :hover. Mamy możliwość manipulacji właściwością className danego elementu z poziomu JavaScript. Pierwsze co zrobimy to poprawimy nieco kod CSS:
li:hover ul{ display: block; }
zamienimy na:
li:hover ul, li.over ul{ display: block; }
Teraz możemy zastosować regułę :hover z CSS dodając klasę over do danego elementu. Musimy też znaleźć sposób, aby powiadomić IE który z elementów ul na stronie jest naszym rozwijanym menu. Możemy to osiągnąć przez nadanie identyfikatora dla głównego elemenu ul:
<ul>
zamienimy na
<ul class="nav">
Ponieważ mamy już sposób na identyfikację głównego elementu ul naszego rozwijanego menu, możemy go uchwycić i przy użyciu pętli dodać do każdego potomnego elementu li obsługę zdarzeń onmouseover i onmouseout. A oto, jak tego dokonać:
startList = function() {
if (document.all&&document.getElementById&&!window.opera) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
}
node.onmouseout=function() {
this.className=this.className.replace(" over", "");
}
}
}
}
}
window.onload=startList;
Po załadowaniu strony wywoływana jest funkcja startList. Sprawdza ona, czy ma do czynienia z IE w wersji 5 lub wyższej przez sprawdzenie istnienia metod document.all i document.getElementById. To dość brutalny sposób, ale za to jest krótki i wdzięczny, a ponieważ zależy nam na kompaktowej metodzie, powinien wystarczyć. Następnie funkcja w pętli „spaceruje” po wszystkich elementach dołączając obsługę zdarzeń onmouseover i onmouseout, które odpowiednio ustawiają lub usuwają klasę over do/z właściwości className danego elementu.
- Paleozoik
- Mezozoik
- Kenozoik
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean faucibus mattis tortor. Vestibulum tempor varius erat. Fusce a felis. In cursus, urna quis pretium scelerisque, leo dolor iaculis velit, dignissim eleifend erat quam sed ipsum. Quisque fermentum vehicula wisi. Integer turpis sem, vehicula sed, ultrices in, convallis ac, erat. Morbi iaculis ante quis dui. Donec sit amet odio nec sapien volutpat imperdiet. Nam nonummy.
I to już wszystko. Z boku możesz sprawdzić działanie tej metody na przykładzie naszego prostego menu.
Całość wygląda dość surowo, gdyż ideą tego artykułu było pokazanie działania rozwijanego menu, ale dzięki potędze CSS wszystko może wyglądać o wiele lepiej. Oczywistym punktem startowym powinno być ustawienie koloru tła (background-color) dla list drugiego poziomu.
Warto odwiedzić
W Internecie można znaleźć sporo stron zawierających przykłady stylowania menu nawigacyjnych opartych na listach. Oto niektóre z nich (w jęz. angielskim):
Oprócz powyższych warto też zapoznać się z nowoczesnymi technikami tworzenia stron w oparciu o CSS: