Scriam acum ceva vreme despre posibilitatea de a crea butoane bogate grafic dar editabile ca text.
Prima problema cu abordarea respectiva era una de optimizare: pentru acelasi buton trebuiau folosite 2 imagini, deci 2 requesturi diferite pe server. In timp, si pe un server mai aglomerat, orice problema de genul asta incepe sa se faca simtita si sa se ceara optimizata.
A doua problema: pe langa asta, m-am mai lovit de o problema: lipsa unui efect la roll-over.
Treaba asta m-a facut sa re-gandesc un pic abordarea intregii chestii, in felul urmator:
1. Inainte foloseam 2 tag-uri, unul in altul, sub forma:
A) <li> <a>buton aici</a> </li>
Noua abordare foloseste tot 2 tag-uri, doar ca de data asta un pic diferit:
B) <a>buton aici<div class=end></div></a>
Noul DIV, marcat cu clasa “end”, are rolul de a defini, grafic, partea din dreapta a butonului. O sa introduc aici o schema explicativa, dupa care o sa continui cu explicatiile mai jos:

Dupa cum se vede in imaginea de mai sus, in loc sa folosim mai multe imagini, vom folosi o singura imagine, suficient de lunga incat sa acopere orice scenariu* si avand inaltimea dubla: un rand pentru starea normala si unul pentru starea de “over”.
* Pentru a preveni depasirea latimii maxime a unui asfel de element se poate folosi oricand combinatia impreuna a urmatoarelor trei proprietati css:
1. max-width pentru a limita latimea butonului la maximul impus aici;
2. white-space: nowrap; pentru a preveni “ruperea” textului pe mai multe randuri;
3. overflow: hidden; pentru a “ascunde” orice text care ar depasi limitele impuse la punctul 1.
Pornind de la premisa ca pentru acest buton/tab vom folosi codul de mai sus ( B) ), hai sa studiem un pic cum vom obtine efectul dorit, pornind de la dimensiunile prezentate in imagine:
1. Paddingul aparent:
a {
padding-top: 8px;
padding-bottom: 5px;
padding-left: 16px;
padding-right: 16px;
}
Dar, daca ne uitam atent, vedem ca in dreapta o parte din “padding” este furata de fapt de DIV-ul “end”. Asa ca vom rescrie un pic regulile de padding pentru a lasa 6 pixeli liberi in dreapta pentru “end”:
a {
padding-top: 8px;
padding-bottom: 5px;
padding-left: 16px;
padding-right: 10px;
}
Nota: pentru ca elementul nostru (<a>) sa se comporte asemeni unui “box” (sa poata accepta proprietati ca “height”, de pilda), mai trebuie un mic artificiu: sa-l declaram ca “block” si sa-i setam un “floating”:
a {
display: block;
float: left;
height: 10px;
}
2. Pozitionarea elementelor
Pentru a putea pozitiona cu precizie (in mod “absolut”) DIV-ul “end”, va trebui ca parintele lui (in acest caz, <a>) sa fie pozitionat “relativ”:
a {
position: relative;
}
iar pe “end” sa-l pozitionam “relativ”:
a .end {
position: absolute;
}
Pentru a “rezerva” apoi spatiul din dreapta necesar afisarii lui “end”, vom adauga o margine in dreapta lui <a>:
a {
margin-right: 6px;
}
si il vom pozitiona absolut pe “end”:
a .end {
right: 0px;
top: 0px;
}
Dar asta ar face ca “end” sa fie afisat in interiorul lui <a>, nu in exterior asa cum ne dorim de fapt. Ca sa-l facem sa se afiseze in exterior il vom “forta” sa fie afisat mai la dreapta, folosind un margin negativ in dreapta lui:
a .end {
margin-right: -6px;
}
In momentul acesta putem sa mai setam cateva proprietati necesare afisarii corecte a celor 2 elemente impreuna, proprietati legate de dimensiunile acestora:
3. Dimensiuni
<a> trebuie sa aiba setata doar inaltimea (tineti minte, intreaga idee e ca latimea lui sa poata varia). Formula de calcul a inaltimii reale este:
IR = IA – P
unde :
IR = inaltimea reala;
IA = inaltimea aparenta;
P = paddingul insumat (top + bottom);
In cazul nostru, rezulta:
IR = IA – P = 23 – 8 – 5 = 10, deci
a {
height: 10px;
}
Cum “end” e doar un element decorativ, fara padding, atunci e foarte usor sa setam inaltimea si latimea lui:
a .end {
height: 23px;
width: 6px;
}
4. Background-urile
Intreaga ideea a tutorialului este de a folosi o singura imagine pentru a obtine toate efectele astea. Asa ca hai sa definim background-urile:
a, a .end {
background-image: url("tab_back.gif");
}
a {background-position: left 0px;}
a .end {background-position: right 0px;}
daca nu e clar inca: primul parametru se refera la alinierea pe orizontala (left / right) iar al doilea la cea pe verticala, in cazul nostru “0px” echivaland cu “top”.
Pana aici avem urmatorul CSS rezultat:
a, a .end {
background-image: url("tab_back.gif");
}
a {
height: 10px;
padding-top: 8px;
padding-bottom: 5px;
padding-left: 16px;
padding-right: 10px;
margin-right: 6px;
display: block;
float: left;
height: 10px;
position: relative;
background-position: left 0px;
}
a .end {
height: 23px;
width: 6px;
margin-right: -6px;
right: 0px;
top: 0px;
position: absolute;
background-position: right 0px;
}
Sa continuam cu effectul de roll-over…
Din imaginea prezentata la inceputul tutorialului ne putem da seama ca pentru a obtine un efect de roll-over e suficient sa “instruim” backgroundurile celor 2 elemente ca, la roll-over, sa se afiseze shiftat in sus, dand in felul acesta efectul dorit. Shiftat cu cat? cu echivalentul IA (inaltimii aparente), care era de 23px in cazul nostru. Asadar:
a:hover {
background-position: left -23px;
}
a:hover .end {
background-position: right -23px;
}
Ovservam ca nu am folosit .end:hover ci a:hover .end. De ce? Pentru ca nu vrem ca “end” sa reactioneze la :hover independent, vrem ca el sa se comporte ca atare numai atunci cand parintele lui o face. Folosind sintaxa de mai sus, ne asiguram de lucrul acesta.
Cam asta ar fi. Spor la codat! 🙂
Note:
1. Daca vreti sa folositi efectul de :hover 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 TAB-uri/Butoane, cel selectat sa fie vizibil ca atare. Solutia preferata de mine este sa marchez elementul selectat cu o clasa (suplimentara), ceva in genul:
<a class=selected>buton aici<div class=end></div></a>
treaba insotita in CSS de urmatoarea completare:
a:hover, a.selected {
background-position: left -23px;
}
a:hover .end, a.selected .end {
background-position: right -23px;
}
aha…
retete de sarmale n-ai? 😛
e clar, meritzi concediu cu plata 😛
acu serios, ingenioasa abordare 😉
Thanks!
Promit sa si citesc in curand tot ce ai zis tu mai sus. 🙂
P.