Taburi cu CSS și jQuery

Taburile reprezintă o modalitate foarte eficientă de organizare a informației. Prima dată când le-am văzut au fost prin Windows 95 și de atunci… N-am mai scăpat de ele. În editoare text, în browsere, mai nou în Adobe CS4, taburile te ajută să organizezi eficient – în funcție de anumiți factori – câteva pagini de informație.

Având în vedere că de câțiva ani se tot încearcă o migrare a aplicațiilor desktop spre online (într-o măsură mai mare sau mai mică), taburile nu puteau lipsi. Fie că sunt cât se poate de seci, încărcând fiecare pagină în parte (cu un refresh al browserului), fie că sunt bazate pe AJAX, încărcând doar conținutul tabului, fie că pur și simplu se află în sursa paginii ascunse iar utilizatorul le vede după ce face un click, taburile există și pe online.

Ca utilizator, taburile sunt foarte simplu de folosit. Dar ca programator, oare cât de simplu sunt de implementat?

Partea ușoară (și nu neapărat cea mai bună)

Cea mai ușoară metodă de a implementa într-un proiect taburi ar reprezenta-o folosirea unei librării gen jQuery UI. Desigur, dacă nu te deranjează să încarci 20kb jQuery și încă vreo 20kb UI (tabs), plus ceva CSS (nu neapărat necesare). Dar hei, ai o grămadă de opțiuni, events și metode pe care oricum nu le vei folosi decât foarte rar (spre deloc, îți spun din experiență).

Partea un pic mai… „grea”

Ce-ar fi dacă… Îți scrii singur o funcție pentru taburi (desigur, nu cu atât de multe opțiuni cum are UI)? Nu sună prea tentant, nu? Dar dacă ți-aș spune că poți face asta în câteva linii de cod scrise răsfirat ? Deja ți-am stârnit interesul! Pentru că, așa cum știe toată lumea, mai puțini KB înseamnă o factură mai mică (la hosting) și un utilizator ceva mai fericit că se încarcă site-ul mai repede. Desigur, la 2-3000 unici/lună nu e mare brânză, dar ia gândește-te la un site cu peste 100.000 unici/lună, ar însemna o economie de vreo 2gb (cel puțin!).

Mark-up

Să vedem cu ce ne murdărim pe mâini. Începem cu puțin html:

<ul class="tabs clearfix">
	<li class="s"><a href="#">Tab 1</a></li>
	<li><a href="#">Tab 2</a></li>
	<li><a href="#">Tab 3</a></li>
	<li><a href="#">Tab 4</a></li>
</ul>

Ca structură, e o simplă listă dezordonată (ce tare sună în română :D ). Clasa clearfix este o metodă inteligentă (mulți mă vor contrazice) de a evita problemele cu elementele ce au un floataplicat. De ce am zis că mulți mă vor contrazice? Pentru că mulți preferă metoda overflow:hidden, dar din păcate, oricât de curat ar părea, aduce câteva probleme în anumite situații. Dacă vrei să folosești overflow:hidden, nimic nu te oprește. Clearfix este o preferință personală :)

Câteva cuvinte despre clearfix am scris în urmă cu câteva luni aici.

Primul element din listă are clasa s (selectat) deoarece arată un pic diferit, astfel încât utilizatorul să știe ce tab este selectat. Această clasă se va schimba în funcție de tabul selectat.

CSS

Dacă am pus clearfix la lista de mai sus, înseamnă că elementele listei vor pluti (hmmm… cred că trebuie să renunț la a mai traduce chestii). Așadar:

.tabs {
	border-bottom:1px solid #ccc;
}
	.tabs li {
		float:left;
		margin-left:10px;
		border: 1px solid #ccc;
		position:relative;
		top:1px;
		background:#fff;
		-moz-border-radius:5px 5px 0 0;
		-webkit-border-radius: 5px 5px 0 0;
		border-radius:5px 5px 0 0;
	}
		.tabs li a {
			display:block;
			line-height:24px;
			padding:0 10px;
			color:#444;
		}
			.tabs li a:hover,
			.tabs li a:focus,
			.tabs li.s a {
				color:#000;	
			}
			.tabs li.s {
				top:2px;
				border-bottom:none;
				background-color:#fefefe
			}

În acest moment, aceste taburi pot fi folosite oriunde, fără pic de javascript. Pe browserele adevărate (FF, Chrome, Safari), taburile au colțurile rotunjite, ceea ce le face mult mai arătoase ;) Desigur, poți folosi sliding doors pentru a face taburile, dar asta ține strict de designer. Iar eu vreau să-ți arăt o tehnică ce ține mai mult de jquery decât de design.

Mici lămuriri despre .tabs li
  • float:left aranjează toate elementele listei unul lângă celălalt
  • position:relative și top:1px ne permit să mutăm puțin mai jos elementul listei, astfel încât linia de jos să fie întreruptă în dreptul tabului selectat
  • border-radius (și toate combinațiile) rotunjesc colțurile (pe browserele ce suportă CSS 3, desigur). ATENŠ¢IE! Dacă ești genul care vrea cu orice preț un fișier valid CSS 2.1, atunci NU ar trebui să folosești astfel de proprietăți (ce țin, așa cum am mai zis, de CSS 3) ;)

The magic

Așa cum am spus mai sus, în momentul acesta ai taburi făcute strict cu CSS. Sunt acele taburi seci, de care am scris la începutul acestui articol. Hai să vedem cum să le facem să nu fie atât de seci. Pentru început, facem o mică modificare asupra codului HTML inițial:

<div class="tabWrapper">
	<ul class="tabs clearfix">
		<li class="s"><a href="#tabId1">Tab 1</a></li>
		<li><a href="#tabId2">Tab 2</a></li>
		<li><a href="#tabId3">Tab 3</a></li>
		<li><a href="#tabId4">Tab 4</a></li>
	</ul>
	
	<div class="tab" id="tabId1">
		<h3>Ut enim ad minim veniam</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisic [...]</p>
	</div><!-- /.tab-->

	<div class="tab" id="tabId2">
		<h3>eiusmod tempor incididunt ut </h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisic [...]</p>
	</div><!-- /.tab-->
	
	<div class="tab" id="tabId3">
		<h3>consectetur adipisicing elit</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisic [...]</p>
	</div><!-- /.tab-->
	
	<div class="tab" id="tabId4">
		<h3>Lorem ipsum dolor sit amet</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisic [...]</p>
	</div><!-- /.tab-->	
</div><!--/.tabWrapper-->

Ce s-a schimbat? Am inclus taburile și conținutul acestora ( .tab ) într-un div mare, din două motive: 1) o organizare mai bună și 2) în cazul în care ai mai multe zone cu taburi într-o pagină, îți permite sa le stilizezi individual. În al doilea rând, fiecare link din taburi are un atribut href acesta corespunde cu id-ul fiecărui div cu conținutul tabului. Îți voi arăta un pic mai jos cum poți face același lucru FĂRĂ a folosi niciun ID ;)

Dacă nu vrei să te complici cu request-uri ajax iar utilizatorul să beneficieze instant de informația din taburi, aceasta e cea mai la îndemână soluție. Ce trebuie să faci pentru asta? În primul rând, trebuie să ascundem conținutul tuturor taburilor, mai puțin cel selectat. Pentru asta avem două metode (sau, dacă adăugăm puțin markup, avem trei metode):

  1. Ascundem conținutul taburilor cu CSS iar când se încarcă scripturile afișăm doar conținutul tabului selectat
  2. Ascundem conținutul taburilor cu JS, ceea ce presupune că vor exista câteva secunde (sau fracțiuni de secundă, depinde de conexiunea utilizatorului) în care conținutul tuturor taburilor va fi vizibil
  3. Adăugăm o clasă (gen s) unui div.tab, după care ascundem din CSS totul în afară de acesta. Această metodă mi se pare prea intruzivă pentru a o folosi. Oricum, dacă nu îți place niciuna din primele două metode, asta e soluția finală

Asta e o alegere ce poate varia de la proiect la proiect, dar de cele mai multe ori prefer să ascund conținutul cu javascript dintr-un motiv foarte simplu: în cazul în care (din varii motive) nu se încarcă toată pagina, conținutul este vizibil utilizatorului. Simplu și eficient.

Varianta pe bază de ID

$('.tabWrapper').each(function(){
	var t=$(this);
	t.find('.tab').hide();
	t.find('.tabs a').click(function(){
		var th=$(this);
		t.find('.tab').hide(); // ascundem toate taburile
		$(th.attr('href')).show(); // în fucție de atributul href (care așa cum am spus mai sus corespunde cu ID-ul pe care îl are conținutul tabului)
		t.find('.tabs .s').removeClass('s');
		th.parent().addClass('s'); // adăugăm clasa s pentru tabul selectat
		return false;
	});
	t.find('.tabs li.s a').click(); // păcălim browserul să facă un click pe tabul selectat
});

Varianta curată (mai simplă și mai neintruzivă)

Așa cum am spus mai sus, sunt două variante pentru a ascunde și a arăta conținutul taburilor: fie pe bază de ID (așa cum am arătat mai sus) fie pe baza succesiunii din cod. A doua variantă este un pic mai inflexibilă deoarece ordinea taburilor în cod trebuie să corespundă cu ordinea elmentelor .tab. Unii consideră o problemă, alții nu (eu fac parte din alții). Astfel, din codul HTML de mai sus eliminăm toate id-urile și referințele spre ele:

<ul class="tabs clearfix">
	<li class="s"><a href="#">Tab 1</a></li>
	<li><a href="#">Tab 2</a></li>
	<li><a href="#">Tab 3</a></li>
	<li><a href="#">Tab 4</a></li>
</ul>
	<div class="tab">
		<h3>Ut enim ad minim veniam</h3>
		<p>Lorem ipsum dolor sit amet, consectetur [...]</p>
	</div><!-- /.tab-->
	<div class="tab">
		<h3>Ut enim ad minim veniam</h3>
		<p>Lorem ipsum dolor sit amet, consectetur [...]</p>
	</div><!-- /.tab-->
	<div class="tab">
		<h3>Ut enim ad minim veniam</h3>
		<p>Lorem ipsum dolor sit amet, consectetur [...]</p>
	</div><!-- /.tab-->
	<div class="tab">
		<h3>Ut enim ad minim veniam</h3>
		<p>Lorem ipsum dolor sit amet, consectetur [...]</p>
	</div><!-- /.tab-->
$('.tabWrapper').each(function(){
	var t=$(this);
	t.find('.tab').hide();
	t.find('.tabs a').click(function(){
		var th=$(this);
		var index = t.find('.tabs a').index(this); // vedem al câtelea tab e selectat (numărătoarea începe de la 0
		t.find('.tab').hide().eq(index).show(); // ascundem toate taburile și îl afișăm pe cel ce corespunde cu indexul setat mai sus
		t.find('.tabs .s').removeClass('s');
		th.parent().addClass('s');
		return false;
	});
	t.find('.tabs li.s a').click();
});

GATA!

În zece linii de cod ai o soluție rapidă (și foarte simplă, ce-i drept) pentru taburi. Probabil într-un viitor nu foarte îndepărtat (în funcție de reacțiile pe care le va genera acest articol) voi pune un al doilea episod în care îți voi arăta cum poți face taburi folosind AJAX, callback-uri (foarte utile!) și taburi bookmark-able (în funcție de tabul selectat se schimbă și url-ul paginii FĂRĂ refresh) sau alte bunătățuri.

20 Comentarii to “Taburi cu CSS și jQuery”

  1. Foarte util tutorialul, mai ales ca o mare parte din designuri, mai nou, au un tab, doua. Ah, si pentru “sliding doors”, vezi ca ai facut tu un tutorial, care se afla aici

  2. Foarte bine explicat! Bravo!

  3. Ionuț Botizan

    Alooo! Mai ușor cu laudele oameni buni! :P

    Ia stai să vedem un pic ce-avem aici…
    * Vorbești de “.clearfix” și “overflow:hidden”, dar nu le explici. Ok, nu-i ăsta scopul tutorialului, dar puteai să explici măcar metoda folosită de tine. Pe lângă faptul că n-ai făcut-o, nici măcar nu ai pus codul CSS în care constă metoda. Dacă folosești o clasă și clasa aia mai e și esențială pentru buna afișare a HTML-ului, atunci cred c-ar trebui să publici și codul ei CSS.
    Apoi, despre gradul de inteligență al metodei “.clearfix” ar fi de discutat. Părerea mea este că e o metodă brutală, care implică atât “murdărirea” codului CSS cu câteva linii în plus și câteva hack-uri, cât și “murdărirea” codului HTML cu o nouă clasă de care te poți lipsi, peste tot pe unde este nevoie de “curățarea” float-ului.
    Metoda “overflow:hidden” nu necesita nici cod HTML și nici cod CSS în plus, singurul lucru ce trebuie adăugat fiind regula “overflow:hidden” părintelui elementelor flotante. Clar, metoda asta creează probleme în cazul unor design-uri mai …”outside the box”, unde elementele din interiorul unui părinte depășesc granițele acestuia…

    * Un alt lucru pe care NU îl consider în regulă este eliminarea id-urilor. Folosirea lor în atributul href nu poate fi considerată o metodă intrusivă, pentru că este normal să fie folosite așa. În prezența acestora și a JavaScript-ului dezactivat, navigarea în pagină rămâne posibilă. În schimb, dacă JS-ul este dezactivat și sunt vizibile toate tab-urile iar conținutul acestora este destul de consistent, vizitatorul va fi nevoit să deruleze mai multe pagini până ajunge la capitolul care-l interesează.
    Apoi ar mai fi considerentele SEO! Poate vrei ca link-urile (tab-urile) să fie într-o anumită ordine, dar blocurile de conținut să apară în altă ordine în sursa paginii, cele mai importante din punct de vedere al conținutului fiind primele.

    * Și ultimul lucru (pentru moment) este folosirea de nume de clase și variabile irelevante:
    – clasa “s” în loc de “selected” sau chiar “selectedTab”
    – variabila “t” care reprezenta “$(this)”
    – variabila “th” pentru “$(this)” într-un alt context (doar pentru că “t” era deja folosit în altă parte…) Eu ți-am mai zis că ție ți-e, de fapt, lene! :P

    Ca sugestii, aș avea:
    * “outline: none;” pe link-uri
    * mai era ceva, da’ am uitat până am terminat de scris povestea… :D

  4. dacă JS-ul este dezactivat

    , mai zi si de CSS ca e dezactivat si ajungem sa vedem siteul in Notepad.

  5. Staicu Ionuț-Bogdan

    Un alt lucru pe care NU îl consider în regulă este eliminarea id-urilor. Folosirea lor în atributul href nu poate fi considerată o metodă intrusivă, pentru că este normal să fie folosite așa.

    Nici nu am spus că ar fi regulă. Am vrut doar să prezint un concept și să arăt că ID-urile nu sunt vitale. În plus, d’asta am și pus două metode de tab-uri. Fiecare le folosește cum consideră de cuviință ;)

    Și ultimul lucru (pentru moment) este folosirea de nume de clase și variabile irelevante:

    Așa acum am zis, ideea din spatele scriptului este prioritară markup-ului. De aceea nu am explicat foarte bine clearfix-ul. În plus, am mai scris despre el aici. Desigur, și acolo s-au găsit destui să mă contreze. Am spus un pic mai sus: este o preferință personală. Poți folosi absolut orice metodă de “ștergere” a float-urilor :)

  6. Ionuț Botizan, mereu vor fi dispute pe anumite tehnici si chiar daca esti perfectionist si oricat ar comenta unii, in multe cazuri 4, 5, 6 linii de cod HTML/CSS in plus nu fac diferenta. Este o vorba care imi place: “Hai sa nu fim mai catolici decat Papa!”.
    Cat despre explicarea fiecarei clase folosite, ai oarecum dreptate, insa depinde la ce nivel de programatori se adreseaza autorul tutorialului.

    Ionuț (Staicu), poate pui un link spre post-ul in care vorbesti de clasa clearfix.

  7. Staicu Ionuț-Bogdan

    Ionuț (Staicu), poate pui un link spre post-ul in care vorbesti de clasa clearfix.

    Done :)

  8. Pentru incepatori http://flowplayer.org/tools/demos/index.html easy like 1,2,3 si fara sa incarci toate prostiile.

  9. Staicu Ionuț-Bogdan

    @Victor, fii SIGUR că taburile de la flowplayer NU sunt atât de mici (în kb) ;)

  10. prăfuitu (a.k.a. Ionuț Botizan)

    @StefanZ
    “Graceful degradation” – sună cunoscut? După principiul ăsta s-a ghidat și Ionuț atunci când a ales să ascundă conținutul tab-urilor inactive folosind JS, pentru ca în cazul în care JS-ul este dezactivat, conținutul să fie totuși disponibil.

    @msd
    Nu mă deranjează 4,5,…,10 linii de cod în plus atâta timp cât își justifică cumva prezența. Chiar nu sunt ăla care se zgârcește la linii de cod sau la kiloocteți în plus.
    Atâta că mi se pare ciudat să adaugi o clasă nouă în CSS cu câteva proprietăți și un “hack”, două, după care să adaugi clasa respectivă tuturor elementelor HTML ce conțin “copii plutitori” (:D iubesc limba română!), în loc de a adăuga o singură proprietate acelui element (“overflow:hidden” sau “overflow:auto”), fără a mai interveni în codul HTML.

  11. Clearfix, clearfix. Eu sunt foarte nervos pe ele, nuștiu de ce, dar mi se face greață cînd le văd, ceva personal cred eu. :-D

    Prefer în cazul dat să scriu pentru .tabs:

    .tabs {
    width: 100%;
    float: left;
    }

    Pentru începători în jQuery e minunat articolul.

  12. Către Ionuț Botizan, outline: none; în cazul dat nu este binevenit. Mulți, inclusiv eu, preferă navigarea folosind doar keyboard-ul, e bine că știi de graceful degradation, dar mai trebuie să citești despre accesibilitate %) Fără supărări.

  13. Staicu Ionuț-Bogdan

    @Nicolae: prea multe float-uri îți dau o bătaie de cap și mai mare.

    @prăfuitu: așa cum am zis, clearfix e o metodă acceptată de unii, hulită de alții. La fel cum unii preferă să folosească un <br clear="both" />, eu prefer clearfix. Simplu, nu? :)

    Către Ionuț Botizan, outline: none; în cazul dat nu este binevenit […]

    Idem. De obicei pun un a:focus. Dar după cum am spus, scopul principal al articolului nu o reprezintă tehnici de CSS :)

  14. * Și ultimul lucru (pentru moment) este folosirea de nume de clase și variabile irelevante:
    – clasa “s” în loc de “selected” sau chiar “selectedTab”
    – variabila “t” care reprezenta “$(this)”
    – variabila “th” pentru “$(this)” într-un alt context (doar pentru că “t” era deja folosit în altă parte…) Eu ți-am mai zis că ție ți-e, de fapt, lene! :P

    Cred ca a vrut sa cachuiasca referinta catre this intr-o variabila locala pentru a creste rapiditatea scriptului;
    Putea sa foloseasca tot “t” in cealalta functie e in alt “scope”

    Bv pt scrierea tutorialului!

  15. Staicu Ionuț-Bogdan

    Putea sa foloseasca tot “t” in cealalta functie e in alt “scope”

    Ba nu putea, că folosește ambele variabile. Și t și th ;)

  16. Sau asa, nu m am uitat atat de adanc :))

  17. prăfuitu ,

    Atâta că mi se pare ciudat să adaugi o clasă nouă în CSS

    In scris e greu sa-mi dau seama de tonul tau si cum privesti exact problema.
    Daca doar ti se pare ciudat, bineinteles, iti respect parerea. Dar daca ai vrut sa “dai in cap” (mult spus, dar sunt sigur ca intelegi) si sa spui “Nu e bine!”, cred ca exagerezi.

    Ar trebui sa facem o intalnire mai mare decat concertul Madonnei, dedicata clasei clearfix. :)

  18. @Nicolae Vartolomei
    Dap, ai dreptate în primul caz – “float:left” mergea foarte bine în cazul de față
    În ce privește accesibilitatea, cred că știu și eu câte ceva… Nu tot, dar destul să știu că pseudo-clasa “:focus” ar fi fost utilă pentru a evidenția tab-urile într-un mod mai plăcut decât un simplu “outline”.

    @Ionut Popa
    Da, știu de ce a creat o nouă variabilă, dar nu la asta mă refeream. Mă refeream la faptul că în loc de
    var t = $(this);
    era mai ușor de urmărit codul dacă ar fi folosit
    var tabWrapper = $(this);

    @msd
    N-am zis că nu-i bună metoda ci doar ca există alta care mie, personal, mi se pare mai bună. Și eu folosesc “.clearfix”-ul, dar numai atunci când “overflow:hidden” sau “float:left” provoacă mai multe probleme decât rezolvă. Am și precizat în primul comentariu că “overflow:hidden” poate crea anumite dificultăți în unele situații, dar nu-s de părere că ar fi cazul aici. (n-am comentat doar să “dau în cap” ;) )

  19. Si daca ai, sa spunem, vreo 7-8 pagini si astea 7-8 pagini sa aiba destul cod iti imaginezi cum s-ar incarca la prima intrare site-ul?
    Cu un 3 linii de PHP si cateva linii de jQuery poti crea ceva mult mai practic. Si bineinteles, ma refer la schimbarea paginilor intr-un site fara refresh.

  20. Super tutorialul ionut.
    Pentru uraciosii care se leaga de aceste metode de clearfix/fuckfix:
    Mai da-va in pastele mamii voastre de carcotasi ca tutorialul este pe alt domeniu…nu va legati de .css-ul si html-ul baiatului; mai ales ca subiectul cu clearfix a fost discutat in vreo 3 posturi pe blogul lui Ionut.

Show trackbacks

Ți-a plăcut articolul? Lasă un comentariu!

You can insert code snippets using BBcode:
[js].[/js] [html].[/html] [php].[/php] [css].[/css]
You can also use some HTML tags:
<blockquote>.</blockquote> <code>.</code> <a href="">.</a> <strong>.</strong> <em>.</em>

windows apple dropbox facebook twitter