:hover

PE SCURT: meniu cu submeniuri, CSS-only (fara JS)

Orice browser modern (si de aici exclud de la bun inceput IE-ul), daca respecta specificatiile CSS, are prezent suportul pentru pseudo-clasa dinamica:hover” pe TOATE elementele, nu numai pe jalnicul si singuraticul < a >.

Nota: Stii deja ca, in CSS, exista o serie de pseudo-clase dinamice (:hover, :active si :focus), pe care, in mod traditional, le asociezi cu “a” ca sa creezi stiluri diferite pentru cele 3 stari ale unui link, sub forma a:hover de pilda.

Browserele moderne, dupa cum ziceam, avand suport complet pentru asta, permit asocierea acestor pseudo-clase la orice element html. Cu alte cuvinte, pot foarte bine sa definesc ceva de genul:

td       {background-color: #cccccc;}
td:hover {background-color: #336699;}

ceea ce va avea ca efect un o schimbare de culoare de background pe td-urile respective, la roll-over evident, fara nici un pic de javascript care sa incarce codul HTML.

Pretty neat, huh? E un feature excelent, pe care pana si super-blamatul de IE7 a inceput sa-l suporte. Numai IE-urile mai vechi inca umbla cu ciunga-n par… Asa ca recomandarea mea e sa urmaresti atat tutorialul cat si exemplele linkate intr-un browser _modern_.

Noah, trecand mai departe, sa vedem la ce poate folosi treaba asta dragutza: Sa ne imaginam ca vrem sa tinem un element html “ascuns” si sa-l facem vizibil atunci cand trecem cu mouse-ul peste “parent-ul” lui. E un scenariu super-cunoscut pentru cine a incercat vreodata sa construiasca un meniu cu submeniuri. Ca sa exemplific, o sa revin la un exemplu cu < li > -uri:

<ul id="menu">
  <li><a href="#">Element 1</a></li>
  <li><a href="#">Element 2</a></li>
  <li><a href="#">Element 3</a></li>
</ul>

Asta ar fi un meniu clasic, simplu (i-am dat un “id” dintr-un motiv relativ simplu: pentru a putea controla mai bine felul in care voi aplica CSS-urile mai tarziu – cu alte cuvinte, daca in acelasi document voi avea si alte ul-uri care vreau sa se comporte normal, atunci voi restrictiona de la inceput felul in care aplic stilurile de redefinire a ul-urilor si li-urilor in css).

Sa zicem ca vrem sa mai bagam in el niste elemente de nivel 2, tot sub forma de < ul > cu < li > -uri:

<ul id="menu">
  <li><a href="#">Element 1</a>
    <ul>
      <li><a href="#">Sub-element 1</a></li>
      <li><a href="#">Sub-element 2</a></li>
      <li><a href="#">Sub-element 3</a></li>
    </ul>
  </li>
  <li><a href="#">Element 1</a>
    <ul>
      <li><a href="#">Sub-element 1</a></li>
      <li><a href="#">Sub-element 2</a></li>
      <li><a href="#">Sub-element 3</a></li>
    </ul>
  </li>
  <li><a href="#">Element 1</a>
    <ul>
      <li><a href="#">Sub-element 1</a></li>
      <li><a href="#">Sub-element 2</a></li>
      <li><a href="#">Sub-element 3</a></li>
    </ul>
  </li>
</ul>

(Poti vedea ce am facut pana acum aici).
Hai sa incepem sa introducem niste stiluri acum! In primul rand voi vrea ca orice < ul > care se gaseste in < ul > – ul cu id=”menu” sa fie ascuns:

#menu ul {display: none;}

Nota: De ce folosesc, pentru display, valoarea none si nu hidden? Pentru ca orice obiect are doua proprietati inerente: vizibilitatea si spatiul ocupat. In timp de hidden are efect doar asupra vizibilitatii (e ca un fel de transparenta: obiectul nu se mai vede, dar spatiul ocupat de el ramane ferm pe pozitii), none are efect asupra ambelor proprietati, ascunzand obiectul complet, si eliberand spatiul ocupat de el.

Gata, am ascuns meniul secundar. Acum vreau ca el sa redevina vizibil atunci cand fac mouseover peste < li > – ul in care se afla:

li:hover ul {display: block;}

(cu alte cuvinte: orice UL care se gaseste intr-un LI care are mouseover va fi afisat ca un block)
Dupa cum poti vedea aici, n-am rezolvat mare branza, desi logica iti spune c-ar fi trebuit s-o rezolvam.

Ce se intampla: fiecare regula CSS are o importanta precisa, pe care o poti calcula numarand pur si simplu elementele care o definesc. Iar fiecare element are la randul lui o valoare diferita in functie de ce tip de element este. Un nod simplu (.clasa_mea de pilda) are valoarea 1, o pseudo-clasa (un :hover de pilda) are valoarea 10, iar un id (#clasa_x de pilda) are valoarea 100. (hihi ce de pilde! 🙂 )

Acum, daca numaram cele 2 reguli de mai sus, pentru prima avem #menu ul (100+1=101) iar pentru a doua avem li:hover ul (10+1=11). Din calculul asta simplu poti sa intelegi acum cum de o regula “mai generala” poate fi mai slaba in importanta decat una “mai privata”, chiar daca logica iti spune in aparenta contrariul. Ce e de facut: simplu, marim “valoarea”celei de-a doua reguli:

#menu li:hover ul {display: block;}

Acum avem #menu li:hover ul (100+10+1=111>101) ceea ce rezolva problema (vezi rezultatul aici).

Daca mai adaugam si niste stiluri ca sa “infrumusetam” toata treaba,

#menu   {width: 10em;}
ul      {margin: 0px; padding: 0px;}
ul ul   {padding-left: 10px;}
li      {list-style-type: none;}
#menu a {display: block; margin: 0; padding: 2px 3px;}
a       {background-color: #CCCCCC; text-decoration: none;
        font-family: Verdana; font-size: 11px;}
a:hover {background-color: #EAEAEA;}

obtinem ceva ce chiar incepe se semene a meniu. Si asta FARA pic de javascript, cu un cod simplu, curat, care la nevoie (in browsere mai retarde) se degradeaza clar si structurat, deci usor de folosit in orice mediu. De-aici incolo (pentru exemplul asta) restul tine de imaginatia ta, ca sa-l faci sa arate cum vrei tu.

IE5/6?

Astea n-o sa inteleaga in veci ce-am discutat pana acum. Noroc ca, in aroganta lor, domnii de la M$ ne-au permis sa redefinim modul in care functioneaza anumite tag-uri HTML folosind seturi de reguli in fisiere de genul htc. Cum asta e deja cu totul alta discutie, o sa te trimit sa citesti mataluta ce zic altii mai destepti, aici, daca ai rabdarea pe care eu pana la urma am avut-o. Bottom-line e ca baietii din linkul cu pricina au programat un astfel de fisier perfect pentru ce avem noi nevoie, si care emuleaza 99% comportamentul lui :hover.

Ca sa faci ca exemplul nostru sa mearga bine si in IE5/6, ia matalutza fisierul asta si salveaza-l in acelasi folder in care ai lucrat tutorialul pana acum, dupa care foloseste comentariile conditionale ca sa fortam IE-ul (si numai pe el) sa “citeasca” neste treburi in plus, si anume:

<!--[if IE]>
<style type="text/css" media="screen">
body          {behavior: url(csshover.htc); font-size: 100%;}
</style>
<![endif]-->

(il instruim pe body sa joace dupa cum ii canta behavior: url(csshover.htc);) Cum NUMAI IE o sa inteleaga treaba asta, celelalte browsere nu vor fi afectate, iar noi obtinem exact ce am vrut. Cum toata treaba de mai sus este in “comentariu”, se valideaza perfect 😀 ceea ce iar e bine.

Evident, lista de probleme de compatibilitate intre browsere nu se opreste aici… Asa ca atat IE7 cat si IE5/6 o sa faca varza din meniul nostru, daca incercam sa-l facem sa arate cat de cat ok.

Solutia? Un alt “hack” de la M$ – posibilitatea de a crea definitii CSS conditional, in functie de browserul detectat. Dupa un pic de tweaking, am obtinut urmatorul set de reguli conditionale, atat pentru IE5/6 cat si pentru IE7:

<!--[if IE]>
<style type="text/css" media="screen">
body        {behavior: url(csshover.htc);}
#menu ul li {float: left; width: 100%;}
li          {border-bottom: solid 1px #CCCCCC; margin-bottom: -1px;}
</style>
<![endif]-->

<!--[if gte IE 7]>
<style type="text/css" media="screen">
#menu ul li {float: none;}
li          {border-bottom: none 0px; margin-bottom: -4px;}
</style>
<![endif]-->

Fisierul final il puteti vedea aici.
Pentru inspiratie, citeste ce-am citit si eu.

Comments (2)

  1. […] si pe alte elemente decat pe cele care-l accepta in mod natural (div-uri etc), atunci dati un ochi aici ca sa vedeti cum puteti obtine asta. 2. Uneori se doreste ca, acolo unde avem mai multe […]

  2. […] :hover effect on elements other than those naturally accepted by the browsers (div-s etc.), then go here and read how to accomplish that. 2. Sometimes, in a context with multiple buttons/tabs, you may be […]

Leave a Reply

Your email address will not be published. Required fields are marked *