Какво съдържа една HTML таблица?

Илия Горанов

Какво съдържа една HTML таблица? Повечето биха казали <table>, <tr> и <td>. Всъщност обаче една таблица може да съдържа много повече информация.

В близкото минало таблиците се използваха за оформяне изгледа на страницата. Това беше така, защото таблиците бяха най-лесния и в същото време най-ефективния инструмент за тази цел. И до днес много разработчици продължават да използват таблици за оформянето на страници. Това обаче е грешно, защото таблицата е предназначена, за да съхранява таблична информация. Заради това последователността на данните в нея е строго определена – отляво надясно и отгоре надолу. А последователността на информацията в таблица използвана за форматиране може да бъде съвсем нелогична. Ето защо е много по-подходящо информацията да се структурира с други инструменти, а форматирането и конкретното подреждане да се зададе чрез CSS.

Правилното подреждане на информацията носи много неочаквани ползи за една страница. На първо място е по-доброто индексиране на информацията от търсещите машини. Тъй като те четат кода, а не го „гледат с очи” интерпретиран на екрана, за тях подредбата на информацията е такава, каквато е в кода, защото той представя структурата на информацията. Друго предимство на добре структурирания код е, че той е достъпен не само за стандартните браузъри, но и за всевъзможни устройства имащи достъп до Интернет – роботи, GSMs, PDAs, четци с гласови синтезатори и други.

Някои разработчици в стремежа си да избегнат употребата на таблици ги отхвърлят 100%. Всяка крайност е неправилна, включително и пълното отказване от таблиците. При наличието на таблични данни, т.е. такива, които са подредени в колони и редове, не само е най-удобно, но и е правилно да се прилагат таблици.

Таблиците биват изключително прости – например съдържащи само няколко колони и само няколко реда. Но таблиците също така биват и доста сложни – например съдържащи групирани данни по определен признак. Повечето таблици имат наименования на колоните, а някои имат и заглавие и описание на таблицата. При групирането на колони или редове нещата загрубяват още повече.

Да започнем с нещо лесно.

Отваряме таблица, в нея добавяме ред, в него добавяме две клетки, след това втори ред, още две клетки, затваряме таблицата.

<table>
<tr>
<td></td>
<td></td>
</tr>
</tr>
<td></td>
<td></td>
</tr>
</table>

За да направите клетките от първия ред заглавия, можете да замените съответните тагове <td> с <th>. От структурна гл.т. това ще означава, че от втори ред надолу таблицата съдържа данни, но на първия ред съдържа заглавието на колоната – типа на данните следващи надолу.

Да преминем към нещо по-сложно.

Тагът <caption>: Тагът се разполага веднага след отварящия таг на таблицата. Съдържа кратко заглавие на таблицата, което в стандартните браузъри се визуализира над нея. Не представлява задължителен елемент, но не вреди.

Тагът <summary>: Тагът се разполага непосредствено след затварящия <caption> таг. Съдържа кратко описание на данните в таблицата. Желателно е ако има такъв таг, да има и <caption>, макарче това не е задължително. Иначе <caption> може да си съществува и сам, без да има описание.

Вертикално групиране: за групиране на данните в колоните се използват таговете <colgroup> и <col>. Всеки от двата може да бъде разположен непосредствено след затварящия таг <summary> или ако той е пропуснат – този, който е преди него. Докато <colgroup> служи за структурно обединяване на колони със сходна информация, <col> служи за присвояване на характерни атрибути да всички клетки в дадена колона от таблицата. Пример за структурно обединяване на колони по съдържание може да бъде таблица – списък с имена на хора, в която има две колони за пол. Ако полът е мъжки – се поставя отметка в колоната М, ако полът е женски – в колоната Ж. Това може да бъде направено с една колона, като отметката е буква, която сочи конкретния пол. Но може да бъде направено и с две структурно обединени колони. За да се посочи броя на обединените колони в една група, може да се посочи атрибут span="n", където n е число по-голямо от единица.

Тагът <col> се използва за визуално обединяване на клетките от една колона в таблицата. Примерно, ако желаете всички клетки в първата колона на една таблица да имат червен фон – можете да зададете на <col> тага за първата колона нужното форматиране и то ще бъде приложено върху всички клетки попадащи в нея. По същия начин могат да бъдат задавани е други атрибути като пренасяне на текста, широчина, шрифт, цвят и други.

Тагът <col> може да съществува както самичък в таблицата, така и вътре в група:

<col />
<col />
<col />

или

<colgroup>
<col />
<col />
</colgroup>
<col />

ако първата и втората колона са еднакви, може да се изпише и така

<colgroup span="2" />
<col />

Тагът <col> също може да има атрибут span="n", където n е число по-голямо от единица. В такива случаи атрибутите важат за съответния брой колони, но те не са обединени структурно или смислово, а само на ниво атрибути.

Глава, тяло и дъно на таблицата:

вече стана дума за тага <th>. С него се създават заглавни клетки в таблицата, които показват какво е съдържанието на дадена колона или ред от таблицата. Освен това обаче, при дълги таблици, които при печат не се събират на един лист е удобно тези заглавия да стоят най-отгоре на всяка страница. Съвременните средства не дават такива големи възможности по отношение на печатането на таблици, но дават възможност това да бъде определено в структурата на кода. По този начин ако имаме правилно подредени данни, един ден, когато браузърите вече могат да печатат HTML таблици с повече възможности, няма да бъде необходимо да се редактират данните. Достатъчно ще бъде да се опише схемата за тяхното извличане и печатане.

Тагът <thead> създава глава в таблицата. Логически погледнато това е онази част от една таблица, която независимо кои данни гледаме в момента, би следвало да стои най-отгоре. Не е задължително тази глава да съдържа само един ред. Възможно е една глава да съдържа два или три реда, когато това е необходимо. Главата се разполага след вертикалното групиране или друг затварящ таг след отварянето на таблицата, когато вертикалното групиране отсъства. Съдържанието на тага е същото като на обикновената таблица – редове, в които има клетки или заглавни клетки.

Тагът <tbody> следва да съдържа табличните данни по същество. В него не бива да се включват обобщаващи редове или заглавията на колоните. И той като <thead> съдържа редове с клетки и заглавни клетки. Разполага се веднага след затварящия <thead> таг.

Тагът <tfoot> е дъното на таблицата. Често се налага да има един ред, в който е посочена сумата от числата в дадена колона или друга обобщаваща информация, която винаги е в долния край на таблицата. Той се разполага след затварящия таг <tbody> и може да бъде пропуснат когато не е необходим. Съдържанието му е същото като това на таговете <thead> и <tbody>.

В общия случай трите части присъстват в кода на една таблица само по веднъж. Но на теория са възможни случаи, при които една и съща таблица да има повече от един <thead>, <tbody> или <tfoot>. Пример за такава таблица е календар. Тогава колоните с имената на дните от седмицата могат да бъдат <thead>, следва <tbody> съдържащо дните от месеца и <tfoot> съдържащ името на месеца. След това може по същата схема да бъде описан следващия месец в същата таблица.

И така, какво имаме дотук?

<table>
<caption></caption>
<summary></summary>
<colgroup>
<col />
<col />
</colgroup>
<col />
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<th></th>
<td></td>
</tr>
<tr>
<th></th>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</tfoot>
</table>

Нека минем на следващ – още по-сложен етап.

Ако желаете да слеете две или повече клетки в таблицата вертикално или хоризонтално. За целта откривате горната лява клетка от групата клетки, които ще бъдат сливани и посочвате атрибутите colspan="n" и rowspan="n", където n са числа по-големи от единица. След това изтрийте кода на клетките, които са под сливащата или са отдясно на сливащата и ще бъдат слети с нея. Имайте предвид, че въпреки сливането на клетки, всяка новополучена клетка също има правоъгълна форма. Т.е. не може да слеете три клетки, които да образуват Г-образна форма. Също така сливането може да се направи както вертикално – с атрибута rowspan="n" (сливане на редове), така и хоризонтално – с атрибута colspan="n" (сливане на колоните), а също и хоризонтално и вертикално едновременно, като се ползват и двата атрибута.

От тук нататък се съмнявам, че има и 1% от читателите, които знаят за тези възможности при проектирането на таблици.

За да може да бъде прочетена правилно една таблица от гласов синтезатор, той трябва да знае коя клетка за кое заглавие се отнася. За това на <th> таговете може да се зададат уникални id="#" атрибути, а на всяка клетка от таблицата да се зададе чрез атрибута headers="#" към заглавната клетка с кой id се отнася. Това очевидно не е много практично решение, защото означава много излишен код. Очевидно е, че всички, или повечето, клетки разположени в една и съща колона са свързани със заглавната клетка на тази колона.

Затова съществува и друг атрибут – scope="" - обхват. Този атрибут се задава на заглавните клетки и следва да описва кои клетки в дадената таблица съдържат информация релевантна на тази заглавна клетка. Най-простият пример е scope="col", което ще означава всички клетки от същата колона. Когато заглавната клетка не е най-горе на колоната, а най-отляво на реда, можете да зададете scope="row", което ще означава, че заглавната клетка се отнася до всички клетки от същия ред. Ако имате обобщаваща колона – както беше примерът с колоната пол, която е съставена от две колони – мъжки и женски. За колоните мъжки и женски можете да зададете scope="col", а за колоната пол, можете да въведете <th colspan="2" scope="colgroup">Пол</th>. По този начин ще бъде посочено, че полът като заглавна клетка се отнася както до клетките от едната колона, така и до клетките от другата колона. По аналогия, атрибутът може да приема и стойност rowgroup.

Представете си обаче още по-сложна таблица. Например такава, в която имате дати по редовете и типове разходи в колоните. Във всяка клетка от таблицата е записано на определена дата какъв е бил разходът от определен вид. В такава таблица често се налага групиране на данните в таблицата по допълнителен критерий. Например всички дати от един и същ месец се обединяват и под всеки месец се дава обобщена информация за месеца. Тогава на всяка клетка може да попада в обхвата на дадена дата, както и да попада в обхвата на даден тип разход. Всяко обобщаване на месец, може да представлява една слята по колоните клетка, която се намира преди датите от съответния месец. И тогава може тази обобщаваща клетка за целия месец да има id="#" атрибут, а клетките с данни от съответния месец да имат атрибут headers="#".

Може би ви е направило впечатление, че атрибутът headers="#" се изписва в множествено число. Това е така, защото той може да съдържа изброени няколко id референции. Представете си още по заплетена ситуация, при която горната таблица освен обединяване по месеци, има и групиране на месеците по години. Тогава може на всяка клетка да посочите не само към кой месец е референтна, но и към коя година. Всичко това дава безкрайни възможности за структурно свързване на данните в една таблица и на практика може да се реализират матрични и многослойни таблични данни по начин, който едновременно позволява те да бъдат представени визуално в една равнина, така и да бъдат лесно обработвани като взаимосвързани данни.

Мислехте си, че това е черешката на сладоледа?

За всяка клетка от таблицата може да бъде посочен атрибут axis="#". Ако тази клетка има атрибут id, в същата група попадат и всички клетки, които имат референция към нея чрез headers="#" атрибута. По този начин, може да се създават линии, по които да се извършва извличане на данни от таблицата. Например може да се зададе axis="date" на всички <th>, които съдържат дата. Може да се зададе axis="january" на <th> обединяващ месец януари, да се зададе axis="expenseType1" за заглавната клетка <th> на разход тип 1. По този начин от таблицата могат да бъдат извлечени данни като сума на разходите от дадена дата или общо разходите през определен месец. Аналогично могат да бъдат извлечени данни и за всички разходи от тип 1. Или разходите от тип 1 в рамките на определен месец.

Тук е важно да се отбележи, че всички тези възможности за обработка на табличните данни са само хипотетични и не са стандартно залегнали в DOM парсерите. Нито пък възможностите за извличане на данни от таблица по определени критерии са приложими със стандартните средства за обработка на Markup код. Но това са стандартни методи за маркирането на информацията и създаване на връзки и това гарантира, че ако различни софтуерни средства предвиждат начин за обработка на данни, то те би следвало да работят по сходен начин. Тук е важно да се отбележи, че всички изброени атрибути: id, headers, scope, axis; могат да се прикачат както към <th>, така и към <td> таговете.

И за десерт

, ако при синтезирането на реч от таблични данни не желаете да се повтарят многократно дългите текстове в заглавните клетки, можете да зададете на всяка заглавна клетка и съкратено описание на свързаното съдържание чрез abbr="" атрибута за абревиатури. По същия начин можете да промените и смисъла на заглавната клетка, ако текстът в нея е изписан в множествено число, а при използването му като представка е нужен в единствено число. Например, ако имате следната таблица:

<table>
<caption>Списък на явилите се за проверката</caption>
<tr>
<th>Имена</th>
<th>Единен граждански номер</th>
</tr>
<tr>
<td>Иван Иванов</td>
<td>0123456789</td>
</tr>
<tr>
<td>Петър Петров</td>
<td>1234567890</td>
</tr>
</table>

При синтезиране на реч от тази таблица ще се получи приблизително следният резултат:

Списък на явилите се за проверката
Имена Иван Иванов, Единен граждански номер 0123456789
Имена Петър Петров, Единен граждански номер 1234567890

Можете да я промените така:

<table>
<caption>Списък на явилите се за проверката</caption>
<tr>
<th abbr="Име" scope="col">Имена</th>
<th abbr="ЕГН" scope="col">Единен граждански номер</th>
</tr>
<tr>
<td>Иван Иванов</td>
<td>0123456789</td>
</tr>
<tr>
<td>Петър Петров</td>
<td>1234567890</td>
</tr>
</table>

И ще получите следния резултат:

Списък на явилите се за проверката
Име Иван Иванов, ЕГН 0123456789
Име Петър Петров, ЕГН 1234567890