Koncept: menu w CSS
05 grudnia, 2007
Już dość dawno temu myślałem nad koncepcją prostego menu, które byłoby oparte jedynie na kodzie XHTML i CSS, a jednocześnie wyglądało przyzwoicie bez wspierania się dodatkową grafiką dla tła.
Efekt prac wygląda następująco:

Żadnej grafiki - sam CSS oraz jedna lista uporządkowana i div pod nią. Całość działa w IE 6/7, Firefoksie 2, Operze >= 8.5 Safari 3.0.4 (na podanych przeglądarkach testowałem - prawdopodobnie na starszych wersjach Firefoksa, Opery i Safari też menu będzie wyglądać poprawnie. Na pewno nie wygląda dobrze na IE < 6 )
Kod XHTML
Jak już przed chwilą napisałem - kod XHTML nie powala złożonością:
<ul id="menu">
<li><a href="#">Home</a></li>
<li><a href="#">Gallery</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Articles</a></li>
<li><a href="#">Forum</a></li>
</ul>
<div id="bar"></div>
Myślę, że nie wymaga on większego komentarza, może poza tym, że element div#bar to ten zielony pasek u dołu menu ;)
O wiele ciekawsze jest kod CSS. Zaprezentuję go reguła po regule...
Kod CSS
Zacznijmy od głównych składników - listy uporządkowanej:
ul#menu{
padding-top: 20px;
list-style-type: none;
border-bottom: 1px solid #9ECA40;
float: left;
width: 100%;
background: #474747;
}
oraz poziomego paska pod nią:
div#bar{
width: 100%;
height: 16px;
border-bottom: 15px solid #96BE40;
border-top: 1px solid #98E03F;
background: #9ECA40;
float: left;
}
Dolne obramowanie listy wraz z dolnym i górnym obramowaniem diva (oraz jego tło) tworzą wspomniany pasek, dzięki czemu uzyskujemy efekt a'la modne niegdyś (nie wiem czy teraz także - ekspertem od grafiki nie jestem :P ) złamanie gradientu tła elementu.
Nie ukrywam, że cały efekt tworzą tutaj odpowiednio (według mnie :P) dobrane kolory - różnice pomiędzy kolorami nie powinny być zbyt wielkie, by całość wyglądała przyzwoicie. W wypadku elementów listy:
ul#menu li{
border: 1px solid #BDD2B9;
border-bottom: 2px solid #95AE94;
margin: 0 5px 0 5px;
float: left;
}
Dodałem jasne obramowanie u góry, z lewej oraz prawej strony, a na dole dodałem ciemniejsze obramowanie - "prawie jak cień" ;)
I na koniec zostaje to co sprawiło najwięcej problemów - tło takie jak w pasku pod menu, ale dla elementów listy.
Do sprawy podszedłem w ten sam sposób jak do paska - ustaliłem wysokość równą połowie realnej wysokości elementu i dodałem obramowanie dolne to tej samej szerokości - całość oczywiście dla linka umieszczonego w elemencie listy:
ul#menu li a{
display: block;
height: 13px;
padding: 0 20px 0 20px;
text-align: center;
background: #ACC1A9;
border-bottom: 13px solid #9DB69C;
font: bold 9px/26px Verdana;
color: #FFF;
text-decoration: none;
}
Potem wystarczyło już tylko ustawić dla tekstu odpowiedni line-height (równy realnej wysokości elementu listy) i właściwie menu było gotowe...
No oczywiście nie zapominamy o efekcie hover:
ul#menu li a:hover{
background: #BDD2B9;
border-bottom: 13px solid #ACC1A9;
}
Przy okazji dzięki display:block dla linka pozbyłem się odwiecznego problemu z hover w IE6
Żeby nie było za łatwo
Jeden problem z IE6 miałem z głowy, ale jak wiemy przeglądarka ta potrafi zepsuć nawet najprostsze rzeczy - prezentowany wcześniej styl CSS i kod XHTML działał wszędzie poza IE6 - problem polegał na tym, że nie bardzo dało się umieścić treść elementu nad jego obramowaniem. Ostatecznie podszedłem do sprawy dość drastycznie i zastosowałem expressions.
Skoro IE6 nie chce mi umieścić tekstu nad obramowaniem uznałem, że trzeba umieścić ów tekst z linka w elemencie span, który zostanie odpowiednio wypozycjonowany. Aby nie kombinować z różnym kodem XHTML dla IE6 i reszty całość wykonuje za nas skrypt.
Podstawą do zadziałania jest poniższy kod:
ul#menu li{
position: relative;
}
ul#menu li a span{
position: absolute;
display: block;
cursor: pointer;
}
Dzięki niemu mogę wypozycjonować w dowolny sposób tekst umieszczony w elemencie span nad obszarem linka. Oczywiście pamiętamy o ustawieniu kursora dla elementu span, bo głupio będzie wyglądać element nad którym raz pojawia się kursor dla linka, a innym razem dla zwykłego tekstu ;)
A teraz pora na krótki skrypt, który naprawi wszelkie niedoskonałości IE6 w kwestii wyglądu naszego menu:
ul#menu li a{
-ie-xp: expression(
this.p ? 0 : (
s = document.createElement('span'),
s.innerHTML = this.innerHTML,
this.innerHTML = '',
this.appendChild(s),
this.style.width = this.firstChild.offsetWidth,
s.style.left = (s.parentNode.offsetWidth-s.offsetWidth)/2,
this.p = 1
)
);
}
Powyższy kod generuje nowy element typu span, kopiuje do niego zawartość elementu linka, którą zaraz po kopiowaniu czyści (w linku). Następnie element span jest umieszczany w linku, a dla linka nadawana jest szerokość równa szerokości elementu potomnego (czyli stworzonego przed chwilą elementu span) - bez tego wszystkie elementy listy miałyby długość 100%. Na koniec pozostaje odpowiednie wypozycjonowanie tekstu w linku - robimy to odejmując od szerokości linka, szerokość tekstu i dzieląc ją przez 2. Dzięki tej operacji nasz tekst jest elegancko wycentrowany.
Menu w akcji można obejrzeć tutaj.
W ten oto sposób stworzyliśmy proste i ładne (według mnie :P) menu nie używając przy tym żadnej grafiki :)
Komentarze do wpisu "Koncept: menu w CSS":
1.
tomek napisał(a):
05 grudnia 2007, 12:40:55
ciekawe. choć wersja z dwoma plikami graficznymi szybka :P
2.
gucman007 napisał(a):
05 grudnia 2007, 13:22:04
Pięknie się prezentuje ;] Teraz jestem chory, jak nie znajdę sobie jakiegoś wyższego rangą zajęcia, to spróbuję zrobić całą stronę opartą o „gradienty CSS” bez grafiki :) zaraziłeś mnie
3.
gucman007 napisał(a):
05 grudnia 2007, 13:24:47
@tomek: z czterema obrazkami ;] bo jeszcze prawa i lewa strona od li. Gdybyś nie zauważył, to szerokość li zależna jest od ilości znaków w nazwie odnośnika :)
4.
wzs napisał(a):
05 grudnia 2007, 16:52:36
Fajniutki i pomysłowe :)
5.
Dziudek napisał(a):
05 grudnia 2007, 19:15:02
@tomek – w sumie jak już się zna sposób to raczej nie ma problemu, bo po prostu trochę kodu CSS dochodzi :)
@gucman007 – ile można ze zwykłej gry kolorów i właściwości CSS wyciągnąć, nieprawdaż ?
6.
pijanyadmin napisał(a):
05 grudnia 2007, 19:54:30
nawet nieźle ;) a mam pytanie „tak jakby na temat” jak oddzielic np. clase w css osobno dla IE7 ? dla IE6 jest tak „html,.klasa{” a w IE7?
7.
Dziudek napisał(a):
05 grudnia 2007, 19:56:27
@pijanyadmin – szczerze mówiąc nigdy takich „cudów” nie stosowałem – ja używam komentarzy warunkowych do tego celu – w wypadku różnych wersji IE sprawują się doskonale i nie ma w pliku CSS bałaganu ;)
8.
pijanyadmin napisał(a):
05 grudnia 2007, 20:01:08
tak, osobny plik css i KW to normalka, normalnie jest tak:
.klasa {margin-top: 10px;}
ale IE6 coś się inaczej to odbiera i trzeba to obeść
html,.klasa {margin-top: 15px;}
a IE7 nie odbiera juz tego z IE6 poprawnie ani tego z glownego css’a ;-)
... chyba że jest inny sposób?
9.
Dziudek napisał(a):
05 grudnia 2007, 20:02:40
@pijanyadmin – a próbowałeś zapisu:
typElementu.klasa{marin-top:10px;}?10.
pijanyadmin napisał(a):
05 grudnia 2007, 20:04:10
tak, i pamietam iż jedynym działającym dobrym sposobem było właśnie obejście tego w osobnym css i dodanie do klasy „html,” tylko nie pamiętam jaki był „znacznik” dla IE7 ;/
11.
Dziudek napisał(a):
05 grudnia 2007, 20:06:19
@pijanyadmin – szczerze mówiąc to nie wiem… Generalnie się z tym problemem nie spotkałem O,o
12.
7335 napisał(a):
19 grudnia 2008, 12:24:13
lol
Dodaj komentarz: