A HTML ‹table› elemét a webdizájnerek hosszú éveken keresztül nem igazán arra használták, amire a szabvány tervezői kitalálták. Egészen a közelmúltig a legtöbb webdizájner – részben a kiadványszerkesztésben szerzett rutinnak „köszönhetően”, részben azért, mert az volt az éppen aktuális trend – számtalan egymásba ágyazott ‹table› elemmel oldotta meg az oldalrészek, oldalelemek elhelyezését. Az oldalakat gyakorlatilag sok kisebb-nagyobb méretű darabra szabdalták, majd ezeket a darabokat töltötték meg képekkel és szövegekkel. Azonban egy ilyen módon kialakított oldalelrendezés esetében szinte a legkisebb dizájnváltoztatás is azt jelentette, hogy a munkát a legelejéről kellett kezdeni. A helyzetet jelentős mértékben rontotta, hogy több, magát profinak mondó WYSIWYG webszerkesztő és grafikai program fejlesztői is ezt a megoldást választották a HTML-export funkciónál, vagyis még ezek a szoftverek is rossz példát mutattak a kezdő webfejlesztőknek.
Így néz ki táblánk „nyers” változata
Szerencsére – néhány őskövületnek nevezhető oldalt és programot leszámítva – a táblázatos elrendezés már a múlté, és a ‹table› elemet többnyire arra használják a weboldalak készítői, amire való: adatok, listák táblázatos megjelenítésére. Mi például a Lorem Ipsum MMIX konferenciára regisztrált előadók és résztvevők listának megjelenítésére alkalmazzuk, ám előtte ismerkedjünk meg egy kicsit közelebbről a táblázatokkal és azok elemeivel.
A táblázat alapelemei
A HTML-táblákat körülbelül úgy kell elképzelni, mint egy táblázatkezelő program egy munkalapját, azaz sorokba és oszlopokba rendezett elemi cellák csoportját.
A tábla funkcionálisan elkülönülő részeit érdemes a megfelelő címkékkel megjelölni
Magát a táblát, vagyis a „munkalapot” egy ‹table›‹/table› páros nyitja meg és zárja le. A táblák sorokból állnak, amelyeket ‹tr›‹/tr› címkék jelölnek, és a sorokon belül találhatóak a cellák, amelyekből két fajta létezik: a standard cellák, amelyeket ‹td›‹/td›, és az ún. fejcellák, amiket ‹th›‹/th› címkékkel kell jelölnünk. Vagyis a lehető legegyszerűbb és legkisebb táblázat így néz ki:
‹table›
‹tr›
‹td›Cella‹/td›
‹/tr›
‹/table›
Ez a kód – természetesen a megfelelő HTML-es környezetbe ágyazva – egy egyetlen cellából álló, vagyis egysoros-egyoszlopos táblázatot jelenít meg. A „Cella” helyett szinte bármilyen összetett HTML-kódsorozatot is írhattunk volna, így táblázat celláin belül megjeleníthetünk több bekezdést, képe(ke)t, de akár hosszabb listákat is.
A hátterekkel és a keretekkel „eljátszogatva” akár 3D-hatású cellákat is létrehozhatunk
Ha a ‹td›Cella‹/td› helyett azt írtuk volna, hogy ‹th›Cella‹/th›, akkor jelen pillanatban csak annyi különbséget látnánk, hogy a „Cella” szöveg félkövér betűkkel jelenik meg, ugyanis míg a standard cellák alapértelmezés szerint normál betűstílussal balra zártan jelennek meg, addig az oszlop vagy sor fejrovatok címei félkövéren és középre igazítva. De mivel a cella szélessége most pontosan megegyezik a tartalom szélességével, ezért a megjelenést nem befolyásolja az igazítás iránya.
Beállíthatjuk a cellán belüli függőleges igazítást is
A ‹table› elemnek nagyon sok attribútumot adhatunk meg, szélsőséges esetben egy táblaindító címke ilyen rémálomszerűen is kinézhetne:
‹table title="Ez a tábla címe" summary=”mintatábla” width="50%" height="100px" border="1" cellspacing="3" cellpadding="2" align="center" bordercolor="#000080" bordercolorlight="#000800" bordercolordark="#080000" background="tablebg.png" bgcolor="#cccccc" frame="above" rules="rows"›
Ezt a fajta attribútumhalmozást több ok miatt is ajánlatos elkerülni. Egyrészt, mert ezeknek a tulajdonságoknak egy jelentős részét szerencsére érvénytelenítették az XHTML megjelenésekor. Másrészt azért, mert ezek egy része erősen böngészőfüggő, azaz vannak olyanok, amelyek hatását csak Internet Explorer, mások pedig csak Firefox alatt láthatjuk. Harmadrészt pedig azért, mert a nem a tartalomhoz kapcsolódó tulajdonságokat nem itt, hanem a stíluslapoknál illik megadni. Márpedig a fenti 15 attribútumból mindössze kettő olyan van, ami a tartalomhoz kapcsolódik: a title, amit akkor jelenítenek meg a böngészők, amikor az egérkurzor a tábla fölött időzik éppen, és a summary, amire pedig akkor van szükség, ha oldalainkat úgy akarjuk elkészíteni, hogy felolvasó szoftvereket használó gyengénlátók és vakok is használni tudják. (E témára egy későbbi leckében még visszatérünk.) Az összes többi tulajdonságot – néhány továbbival kiegészítve – inkább az oldalhoz kapcsolt CSS-állományban érdemes megadnunk. (A képen látható és a CD/DVD-mellékleten található példában azért maradt benne néhány attribútum, mert ennél még nem használtunk CSS-t, de azért szerettük volna, ha jól látszanak a tábla részei.)
A sorok esetében, vagyis a ‹tr› címkéknél az az érdekes, hogy az akár attribútummal, akár a stílusokkal ezekhez rendelt tulajdonságok szinte mindegyike tulajdonképpen nem is ezek kinézetét változtatja meg, hanem a sorban található cellákét. Így például az align="center" attribútum vagy a text-align: center; stílus nem a sort fogja középre igazítani, hanem a sorban található valamennyi cella tartalmát (amennyiben az egyes celláknál ezt felül nem bíráljuk). Miután a mégiscsak a cellákban található a táblázatok érdemi része, így érthető, hogy ezeknél találjuk a legtöbb kimondottan a tartalommal kapcsolatos attribútumot, azonban ezek többségét (abbr, axis, headers, scope stb.) nem a böngésző-, hanem a felolvasó programok képesek értelmezni.
A cellaelemekhez tartozik két olyan attribútum is, amelyek tulajdonképpen formaiak, mégsem a stílusoknál, hanem az (X)HTML-kódban kell megadnunk. A cellák colspan és a rowspan tulajdonságai ugyanis azt mondják meg a böngészőknek, hogy a tábla kirajzolásakor az adott cellát mennyi szomszédos oszlop (colspan) és/vagy sor (rowspan) cellával kell összevonni. Ezek használata elég egyszerű, azonban nagy odafigyelést igényel, ugyanis roppant könnyű elrontani, főként összetett táblafejek tervezésekor. Ugyanis, ha egy ötoszlopos táblázat első cellájában azt adjuk meg, hogy össze kell vonni az első három oszlopot (‹td colspan="3"›), akkor ezt követően már csak két további ‹td› elem következhet (már ha ebből az első nem ‹td colspan="2"›, hiszen akkor elfogytak az oszlopaink. Hasonlóképpen, ha azt adjuk meg az első cellánál, hogy ‹td rowspan="3"›, akkor a következő két sorban már csak 4-4 üres cella marad. A böngészők ráadásul semmilyen hibaüzenetet nem adnak, és a különféle validátorok sem veszik észre, ha elrontottuk a cellaösszevonásokat. Ilyenkor viszont az eredmény néha igencsak furcsán fog kinézni a képernyőn.
Részekre bontva
Kisebb táblázatoknál nem annyira érdekes, azonban az összetett fejszerkezetű, vagy hosszabb, több tíz, esetleg több száz soros táblázatok esetében többszörösen is megéri a táblák funkcionális részeit elkülöníteni.
Először is a ‹table› elemen belül – de feltétlenül a nyitócímkét követően – megadhatunk egy táblacímet (‹caption›‹/caption›), amelynek megadhatjuk ugyan akár attribútummal, akár stílussal, hogy a tábla melyik oldalán helyezkedjen el, azonban a Firefoxot leszámítva minden böngésző a tábla tetején fogja megjeleníteni ezt a címet.
A címet követően használhatunk ‹col› és ‹colgroup› elemeket az egyes oszlopok egyszerűbb formázására (például az első oszlop legyen kék és balra zárt, a második oszlop legyen piros és középre igazított, a többi pedig zöld és jobbra zárt), ám sajnos – mondhatni természetesen – ez sem igazán úgy működik a böngészőkben, ahogyan azt a szabvány megalkotói megálmodták. Egyébként némiképp meglepő módon az „oszlopok előformázása” még leginkább a Microsoft böngészőjében működik korrekten, a többi „modern böngészőben” hol az igazítás, hol a színezés vész el.
Amikor a ‹table› elemet arra használjuk, amire leginkább való, vagyis szöveges és numerikus adatokat tartalmazó táblázatok megjelenítésére, akkor érdemes nemcsak formázással, hanem a megfelelő címkékkel tartalmilag is elkülöníteni a táblafejet (‹thead›), a táblateste(ke)t (‹tbody›), és ha van, akkor a táblák láb részét (‹tfoot›). Így egy szépen tagolt tábla valahogy így néz ki:
‹table›
‹caption›Ez a tábla címe‹/caption›
‹thead›
‹tr›
‹th›Táblafej‹/th›
‹th›Első oszlop‹/th›
‹th›Második oszlop‹/th›
‹th›Harmadik oszlop‹/th›
‹/tr›
‹/thead›
‹tfoot›
‹tr›
‹td colspan="4"›lábjegyzetek‹/td›
‹/tr›
‹/tfoot›
‹tbody›
‹tr›
‹th›Első sor‹/th›
‹td›Cella 1/1‹/td›
‹td›Cella 1/2‹/td›
‹td›Cella 1/3‹/td›
‹/tr›
‹tr›
‹th›Második sor‹/th›
‹td›Cella 2/1‹/td›
‹td›Cella 2/2‹/td›
‹td›Cella 2/3‹/td›
‹/tr›
‹tr›
‹th›Harmadik sor‹/th›
‹td›Cella 3/1‹/td›
‹td›Cella 3/2‹/td›
‹td›Cella 3/3‹/td›
‹/tr›
‹/tbody›
‹/table›
Viszonylag ritkán használjuk ki, de egyes alkalmakkor jól jöhet, ha tudjuk, hogy míg táblafejből és táblalábból csak egy-egy lehet, addig egy tábla tetszőleges számú táblatestet tartalmazhat.
A táblastílusok megadásánál is nagy segítséget jelent, ha az egyes részeket elkülönítjük a megfelelő tagekkel
A táblarészek elkülönítésének több előnye is van. Egyrészt nem kell feleslegesen osztályokat létrehoznunk ahhoz, hogy különbözőképpen formázhassunk a táblafejek és a táblatestek celláit, hiszen amíg a CSS-ben a th jelentheti mind a táblafej, mind a táblatest fejcelláit, addig a thead th és tbody th jelölők egyértelműsítik, hogy melyik táblarész celláira is gondoltunk. Az sem utolsó szempont, hogy így sokkal egyszerűbben hivatkozhatunk JavaScriptből is a táblák egyes részeire, ráadásul az esetlegesen több részre bontott táblatestdarabokat is külön-külön kezelhetjük (ahogyan azt a későbbiekben még látni fogjuk). Ezenkívül a nagyon hosszú táblák esetében az sem elhanyagolható tényező, hogy a Firefox (de remélhetőleg hamarosan a többi böngésző is) nyomtatáskor a táblafejet és táblalábat megismétli minden oldal tetején és alján.
Táblastílusok
Amikor egy táblát formázunk, akkor túlnyomó többségben ugyanazokat a stílustulajdonságokat adjuk meg, amiket például egy ‹div› esetében. Vagyis meghatározzuk a szélességét (width), a margóját (margin), a helykitöltést (padding), a keretet (border), ami ez esetben a tábla külső keretét jelenti, esetleg a háttérszínét, -mintáját (background), bár ez utóbbi néhány extra kivételtől igencsak ellenjavallt, valamint megadhatjuk az adott tábla alapértelmezett betűtípusát (font-family), -méretét (font-size), -stílusát (font-weight és font-style), -színét (color), és minden egyéb szövegjellemzőt.
Természetesen a táblaelemekhez különféle stílusokat rendelhetünk
Igazából csak négy olyan stílustulajdonság van, ami kimondottan a ‹table› elemekre jellemző. A table-layout azt mondja meg a böngészőnek, hogy a megadott oszlopszélességek „kőbe vésettek-e” (fixed), vagy a tartalom szétnyomhatja-e az egyes cellákat, így az egész oszlopot (auto). Ha megnézünk egy HTML-táblázatot, láthatjuk, hogy nemcsak magának a táblázatnak, hanem az egyes celláknak is vannak, lehetnek külön keretei. A border-collapse tulajdonsággal adhatjuk azt meg, hogy a böngészőnek a tábla kirajzolásakor ezeket a cellakereteket össze kell-e vonnia (collapse), vagy maradjanak az alapértelmezés szerint különállóak (separate). Utóbbi esetben még azt is megadhatjuk, hogy mekkora legyen az egyes cellakeretek közötti távolság (border-spacing). Ez a tulajdonság annyival tud többet a cellspacing attribútumnál, hogy két értéket is megadhatunk neki, amelyek közül az első a vízszintes, a második pedig a függőleges távolságot fogja jelenteni. Ha egy táblázatnak vannak üres cellái, és a cellakeretek szeparáltak, akkor még azt is eldönthetjük, hogy ezeknek az üres celláknak megjelenjenek-e a keretei (empty-cells: show), vagy sem (empty-cells: hide). Igazából a tábláknak van még egy ötödik tulajdonsága is, a cím helyét meghatározó caption-side, de ahogyan az korábban említettük, ez csak Firefox alatt fejti ki hatását.
A cellakeretekből cellarácsokat hozhatunk létre a border-collapse stílus segítségével
A táblasorokhoz általában azokat a stílustulajdonságokat szokás rendelni, amelyek a sor vagy sorok valamennyi cellájára vonatkoznak, ugyanakkor eltérnek a tábla(rész)nél megadottaktól. A táblázatok cellái esetében már csak azokat a stílustulajdonságokat kell megadnunk, amelyeket sem tábla(rész), sem sor korábban nem definiáltunk. Így például, ha különböző stílusú oszlopokat, vagy esetleg látványos, akár 3D-hatású cellákat szeretnénk, akkor érdemes különféle cellaosztályokat létrehoznunk.
Szükség esetén igen összetett táblafejeket is összeállíthatunk a cellák vízszintes és függőleges összevonásával
Csíkos táblák
A Mesterfogások rovat egy korábbi cikkében Sümegi András részletesen bemutatta, hogyan lehet a Dreamweaver segítségével szép „zebracsíkos” táblákat létrehozni. A sorok váltakozó színezése nem(csak) azért fontos sokszor, mert így illusztrációként is szebben mutat a tábla, hanem azért is, mert a csíkoknak köszönhetően sokkal könnyebb átlátni még a több oszlopból álló táblázatokat is. A cikkben bemutatott megoldás kiválóan működik, amíg viszonylag kevés sorból álló táblázatot kell „kifestenünk”, és az sem árt, ha nem kell sűrűn a 2-3. pozícióba új sort beszúrnunk, hiszen egy ilyen módosítást az összes alatta levő soron „át kell vezetnünk”. De mit tegyünk akkor, ha táblázatunk több tucatnyi sorból áll, vagy ha rendszeresen kell újabb és újabb sorokkal bővítenünk? Ilyenkor jön jól a JavaScript, ami majd megoldja helyettünk ezt a feladatot is.
Az a tábla is olyan mint a korábbiak, csak egy kicsit több sorból és oszlopból áll
Előkészítés gyanánt – a dreamweaveres megoldáshoz hasonlóan – hozzunk létre két új osztályt (például even és odd néven), amelyek csak a háttér színét fogják az egyes sorokban megváltoztatni, sőt, egy kis extraként készítsünk el(ő) egy harmadik osztályt is (mondjuk activerow), amelynek egyrészt adjunk egy harmadik, az előző kettőhöz harmonizáló háttérszínt, másrészt az egérkurzor alakját ne engedjük a szövegek fölött sem megváltozni:
.odd { background: #e8e5cf; }
.even { background: #d6d1aa; }
.activerow { background: #c2bb7e; cursor: default; }
Az alap stíluslapot kibővítjük néhány új osztállyal – amiket majd menetközben rendelünk az egyes elemekhez
Amennyiben biztos, ami biztos alapon celláinkat ellátjuk valamilyen kerettel, hogy akkor is egész biztosan átláthatóak maradjanak, amennyiben valamiért nem fut le a JavaScript program, úgy szükségünk lesz még egy „segédosztályra”, aminek segítségével a keret zavaró részeit tudjuk majd egyszerűen eltávolítani:
.noborder { border-top: none; border-bottom: none; }
Miután készen vagyunk a stíluslap „preparálásával”, még annyit tegyünk meg, hogy azon táblá(i)nkhoz, ami(ke)t szeretnénk csíkosra festeni, adjunk hozzá egy „zebra” osztályt (‹table class="zebra"›). Most már minden előkészülettel készen vagyunk, nekikezdhetünk táblacsíkozó programunknak.
Amíg a program nem fut le, így néz ki táblázatunk
Ahogyan legutóbb, úgy ezúttal is szükségünk lesz egy oldalinicializáló függvényre (function initPage() {}), és az utasításra, ami ezt a függvényt elindítja az oldal betöltődését követően (window.onload = initPage;). Szintén a múlt havihoz hasonlóan először is egy tömbbe összeszedjük a dokumentumban található összes table elemet:
var tables = document.getElementsByTagName("table");
Ezután szükségünk lesz egy ciklusra, ami végigmegy a tables összes elemén, és kiválogatja közülük azokat, amelyeknek az osztálynevében megtalálható a zebra szöveg:
for (var t = 0; t ‹ tables.length; t++) {
if (tables[t].className.indexOf("zebra") › -1)
...
Mint említettük, egy táblának több táblateste is lehet, ezért mindegyik táblatest minden során végig kell mennünk, és a páros sorok osztálynevéhez hozzá kell adnunk az even, a páratlanékhoz pedig odd osztályt. Azt, hogy melyik sor páros és melyik páratlan, úgy döntjük el, hogy megnézzük, kettővel elosztva nulla lesz-e a maradék:
for (var b = 0; b ‹ tables[t].tBodies.length; b++) {
for (var r = 0; r ‹ tables[t].tBodies[b].rows.length; r++) {
tables[t].tBodies[b].rows[r].className += (r % 2 == 0) ? " even" : " odd";
}
}
Ha JavaScript programunkat „hozzákötjük” a táblázatot tartalmazó HTML-állományhoz, majd ez utóbbit betöltjük egy böngészőbe, akkor már láthatjuk is munkánk első gyümölcsét, egy szép csíkos táblát.
Egy rövid program eredményeképpen táblázatunk szép csíkos, így némiképp áttekinthetőbb lesz
Azonban még nem használtuk fel sem az activerow, sem a noborder osztályunkat – utóbbi miatt ráadásul még nemkívánatos vonalak tarkítják táblázatunkat. Éppen ezért ciklusunkat tovább bővítjük egy kicsit. A következő két programsor gondoskodik arról, hogy amikor az egér egy táblatest sorának bármelyik cellája fölé ér (onmouseover), akkor az activerow osztály segítségével átszínezzük a sor hátterét, illetve amikor elvisszük a sor fölül az egeret (onmouseout), akkor az activerow osztály eltávolításával a sor visszakapja eredeti színét:
tables[t].tBodies[b].rows[r].onmouseover = function() { this.className += " activerow"; }
tables[t].tBodies[b].rows[r].onmouseout = function() { this.className = this.className.replace("activerow", ""); }
Most már nincs is más dolgunk, mint végigmenni a sor összes celláján, hogy a noborder osztály hozzáadásával eltávolítsuk a cellák kereteinek felesleges vonalait:
for (var c = 0; c ‹ tables[t].tBodies[b].rows[r].cells.length; c++) {
tables[t].tBodies[b].rows[r].cells[c].className += " noborder";
}
Még Internet Explorer alatt is működni fog a JavaScript-alapú „hover”
Rendezett táblák
Egyes táblázatok, táblázatba rendezett listák esetén felmerül az igény, hogy jó lenne a táblát egy másik oszlop szerint rendezni. Ezt sokszor lehetővé is teszik a számunkra az oldal gazdái, ám többnyire úgy, hogy a szerveren található program újra lekérdezi az adatokat az új rendezési szempont szerint, majd elküldi számunkra az újragenerált HTML-oldalt. Még akkor is, ha egyébként minden szükséges információ megtalálható a mi gépünkön is. Nem lenne egyszerűbb ezeket a táblákat, listákat helyben rendezni? Dehogynem.
A Firebuggal is ellenőrizhetjük, hogy az egyes sorokhoz hozzárendeltük-e a megfelelő osztályokat
Korábbi oldalinicializáló programunkat egészítsük ki azzal, hogy a sortable azonosítójú tábla fejsorának minden celláját olyan hivatkozássá alakítjuk, amely meghív egy JavaScript függvényt:
if (tables[t].id == "sortable") {
for (var c = 0; c ‹ tables[t].tHead.rows[0].cells.length; c++) {
var newLink = document.createElement("a");
newLink.href="javascript:sortTable(" + (c + 1) + ")";
var children = tables[t].tHead.rows[0].cells[c].childNodes;
for (var n = 0; n ‹ children.length; n++) {
newLink.appendChild(children[n]);
}
tables[t].tHead.rows[0].cells[c].appendChild(newLink);
}
}
A sortTable funkció az adott oszlop szerint rendezi táblánkat. A teljes program letölthető innen
Miután létrehoztunk egy új link elemet a createElement metódussal, annak hivatkozásának (href) beállítjuk a sortTable JavaScript függvényt, paraméterként az oszlop sorszámát megadva. Kivételesen azért egytől indítjuk a számozást, mert a negatív számmal azt fogjuk jelölni, hogy a tábla csökkenő sorrendbe rendezett, és a mínusz nulla nem igazán alkalmas ennek a jelölésére.
A program lefutása után a táblafej celláiban megjelennek a hivatkozások
A sortTable függvény – kissé leegyszerűsítve – nem csinál mást, mint egyesével beolvassa a táblatestek celláinak tartalmát és stílusait egy objektumtömbbe (26–33. sorok), lerendezi azt (36. sor), majd az átrendezett táblarészt visszaírja az adott táblatestbe (39–44. sor). A munka érdemi részét tulajdonképpen a sortFn függvény végzi (53–99. sor), amelyik segít a JavaScript rendezőmetódusának, hogy az a többdimenziós objektumtömböt le tudja rendezni a kívánt módon. Ehhez amennyiben szükséges a szövegekből eltávolítja az ékezeteket (removeAccents), hogy azok ne zavarják össze a rendezést (az ékezetes karaktereknek teljesen más a kódja), a magyar számformátumból a JavaScript számára is érthető számokat hoz létre, és gondoskodik arról, hogy az esetlegesen hiányzó adatok („..” vagy „–”) se okozzanak problémát (63–71. és 73–81. sorok).
A táblafejre kattintva a program az adott oszlop szerint rendezi le a táblázatot
A sortFn függvénynek (aminek egyébként bármilyen más nevet is választhattunk volna) egy számot kell visszaadnia minden egyes értékpárnál, ami ha nulla, akkor a sort metódus úgy veszi, hogy a két érték egyenlő, ha negatív, akkor az első, ha pedig pozitív, akkor a második érték a nagyobb. Miután a sort mindig növekvő sorrendbe rendez, ezért ha csökkenő sorrendet szeretnénk létrehozni, akkor a sortFn-nek fordított eredményt kell „hazudnia”, ezért van a return végén a (sortCol ‹ 0) ? -1: 1).
Mindezeken túl a sortTable még arról is gondoskodik, hogy a táblafejen valamilyen módon (háttérszín vagy háttérkép) jelezni tudjuk, hogy melyik oszlop szerint és milyen irányba rendezett táblánk (11–14. és 47–48. sorok).