Tutorial

Piotr Petrus


W dobie standardów i układów stron tworzonych za pomocą sekcji div wielu autorów stron zapomina o tabelach kompletnie. Wszakże odradzano tak gorąco ich stosowania przy projektowaniu kolumn witryny. Nie znaczy to jednak, że tabele same w sobie są złe. O wiele bardziej zgubny wpływ ma niezrozumienie ich przeznaczenia w dokumencie HTML.

Numer 16 (2/2006) • 31 maja 2006


Nicholas Di Genova : Minigaleria

Piotr Petrus. Semantyczne tabele.

Ilustracja: Nicholas Di Genova


Semantyczne tabele


Za pomocą tabel prezentujemy tabelaryczne dane. Podsumowanie ocen na koniec semestru, lista zakupów z ilością produktu i jego ceną, wartości sinusów kątów albo układ okresowy pierwiastków - te dane należy przedstawiać w tabelach.

Zazwyczaj także wszelkie informacje w postaci siatki powinno się wrzucać do tabelek. Mam tutaj na myśli informacje, a nie wizualne elementy strony. Jeśli projektujemy panel użytkownika do systemu zarządzania zawartością, to lista użytkowników wraz z zezwoleniami i liczbą wpisanych artykułów będzie w formie tabeli. Mimo, że da się rozplanować tekst pozycjonując go - zawsze zastanów się jaki typ danych będziesz prezentować.

Zacznijmy jednak od totalnych podstaw, czyli struktury znaczników.

Podstawy

Struktura zwykłej tabeli może wyglądać tak:

  1. <table>
  2. <tr>
  3. <td>Lista zakupów</td>
  4. <td>Cena (PLN)</td>
  5. </tr>
  6. <tr>
  7. <td>Jogurt</td>
  8. <td>1,5</td>
  9. </tr>
  10. <tr>
  11. <td>Kurczak</td>
  12. <td>12</td>
  13. </tr>
  14. </table>

Element table jest pojemnikiem dla komórek (td - table data) ułożonych w wiersze (tr - table row). Tak złożona tabela przybrała by domyślnie taki wygląd. Nie wygląda to ślicznie, ale od czego mamy style. Parę reguł i tabela wygląda o wiele lepiej.

Co gdybyśmy zechcieli mieć komórkę zajmującą parę wierszy bądź kolumn? Należy zaaplikować jej atrybut colspan bądź rowspan.

  1. <table>
  2. <tr>
  3. <td colspan="2">Cena</td>
  4. </tr>
  5. <tr>
  6. <td>PLN</td>
  7. <td>EUR</td>
  8. </tr>
  9. .
  10. </table>

W tym przykładzie komórka Cena rozszerzy się wypełniając miejsce dwóch kolumn w swoim wierszu (tr).

Tabelki nie ograniczają się jednak do kolumn i wierszy wypełnionych danymi. Istnieje o wiele więcej elementów i atrybutów jakie mogą posiadać. I właśnie pełni wykorzystując ten element HTML można znacznie usprawnić dostęp do zaprezentowanych danych.

Po pierwsze należałoby się zastanowić czemu w tabeli górny wiersz pierwszego przykładu nie jest zaznaczony w odpowiedni sposób - w końcu to nagłówek z dwoma kategoriami danych. W HTML występuje element służący do umieszczenia takiej informacji. Mowa o elemencie th - table header. Zamieńmy kod tamtej małej tabelki:

  1. <table>
  2. <tr>
  3. <th>Lista zakupów</th>
  4. <th>Cena (PLN)</th>
  5. </tr>
  6. <tr>
  7. <td>Jogurt</td>
  8. <td>1,5</td>
  9. </tr>
  10. <tr>
  11. <td>Kurczak</td>
  12. <td>12</td>
  13. </tr>
  14. </table>

Przeglądarki w większości pogrubią dane w komórkach nagłówka oraz wycentrują, ale nie jest to rzecz niemożliwa do zmiany, wystarczy użyć CSS aby pozbyć się pogrubienia i powiedzmy dodać ładne pastelowe tło.

  1. th {
  2. font-weight: normal;
  3. background-color: #FBFCD6;
  4. text-align: left;
  5. }

Teraz tak to wygląda. Gdyby się okazało, że nie chcemy aby tekst "Lista zakupów" został złamany w połowie, bo tak się może przydarzyć gdy zabraknie miejsca, nie używajmy twardych spacji (&nbsp;) ani atrybutów w strukturze tabeli. Zamiast tego potraktujmy nagłówek CSS-em:

  1. th {
  2. white-space: nowrap;
  3. }

Podany przykład nie oznacza oczywiście, że nagłówki mogą występować tylko w pionie. Spójrzmy na przykład dwuwymiarowy:

  1. <table>
  2. <tr>
  3. <td></td>
  4. <th>Liczba atomowa</th>
  5. <th>Masa atomowa (u)</th>
  6. </tr>
  7. <tr>
  8. <th>Wodór</th>
  9. <td>1</td>
  10. <td>1</td>
  11. </tr>
  12. <tr>
  13. <th>Tlen</th>
  14. <td>8</td>
  15. <td>16</td>
  16. </tr>
  17. </table>

Prezentacja takiej tabeli wydaje się teraz o wiele lepsza. Należałoby się teraz zastanowić nad jej dostępnością. Wizualnie widać która kolumna i który wiersz łączą się z nagłówkiem. Co jednak z czytnikami ekranu? Przez dodanie atrybutu scope (ang. zakres) możliwe jest wskazanie powiązania komórek nagłówka z wieszem bądź kolumną - col dla kolumn, a row dla wierszy.

Nie sposób zobaczyć efektów działania tych atrybutów w przeglądarce, więc po co mielibyśmy je umieszczać? Choćby właśnie dla dostępności. Nic to nie kosztuje, a pozwala upewnić się że wszyscy użytkownicy skorzystają z danych umieszczonych w tabeli. Można zapytać po co tyle wysiłku dla tych czytników ekranów, prawda? Cóż, nikt nie każe stosować ułatwień, ale także że nikt nie każe stosować div'ów i CSS'a - ale naszym celem jest tworzenie nowoczesnej i dostępnej sieci.

Co więcej - być może nowoczesne urządzenia przenośne nagle wprowadzą technologię wykorzystującą takie atrybuty, aby ułatwić rozeznanie w danych na małym ekranie? Warto być przygotowanym na to wcześniej.

  1. <table>
  2. <tr>
  3. <td></td>
  4. <th scope="col">Liczba atomowa</th>
  5. <th scope="col">Masa atomowa (u)</th>
  6. </tr>
  7. <tr>
  8. <th scope="row">Wodór</th>
  9. <td>1</td>
  10. <td>1</td>
  11. </tr>
  12. <tr>
  13. <th scope="row">Tlen</th>
  14. <td>8</td>
  15. <td>16</td>
  16. </tr>
  17. </table>

Co ważne - przez dodanie tych atrybutów wygląd tabeli nie zmieni się ani trochę. Także jej zachowanie nie ulegnie zmianie. Jedyne co osiągamy to przejrzystość kodu i ułatwienie dla, na przykład, niewidomych.

Kolejnym elementem wartym poznania jest caption. Umieszczony wewnątrz tabelki pozwala na zgrabne dodanie do niej podpisu. Jest to dobry nawyk, który pozwala od razu zorientować się o danych występujących w komórkach bez ich analizowania.

  1. <table>
  2. <caption>Tab 1. Lista rzeczy do kupienia na jutro w supermarkecie</caption>
  3. <tr>
  4. <th>Lista zakupów</th>
  5. .
  6. </table>

Domyślne położenie podpisu na górze tabelki jest może i wygodne dla programów czytających tekst z ekranu na głos, zanim przystąpią do analizowania danych, ale w większości przypadków nie wygląda to ładnie. Wyjściem nie jest jednak przełożenie go na koniec w kodzie tabelki - musi on być zawsze pierwszym elementem wewnątrz table. Można ten stan rzeczy zmienić po prostu przez CSS:

  1. caption {
  2. caption-side: bottom;
  3. }

Rezultat. Pamiętaj, aby nie umieszczać za dużo informacji w caption. Powinno być to szybkie do ogarnięcia wzrokiem podsumowanie tabeli. Natomiast w celu umieszczenia detali i szczegółowego opisu możesz posłużyć się atrybutem summary dla głównego elementu table.

  1. <table summary="">
  2. <tr>
  3. <td></td>
  4. .
  5. </table>

Dobrym nawykiem jest też korzystanie z atrybutu abbr dla komórek nagłówka. Pozwala on na skrócenie odczytywanego tekstu za drugim, trzecim i kolejnym razem.

  1. <table>
  2. <tr>
  3. <th abbr="Produkt">Lista zakupów</th>
  4. <th abbr="Cena">Cena (PLN)</th>
  5. </tr>
  6. <tr>
  7. <td>Jogurt</td>
  8. <td>1,5</td>
  9. </tr>
  10. <tr>
  11. <td>Kurczak</td>
  12. <td>12</td>
  13. </tr>
  14. </table>

Za pierwszym razem użytkownik czytnika ekranu dostanie informację "Lista zakupów" wraz z "Jogurt", za kolejnym już "Produkt" razem z "Kurczak". Podobnie nie będzie trzeba powtarzać, że cena jest podana w PLN.

Grupowanie wierszy

Wrócmy jednak do samej struktury tabelek. Istnieje dość ciekawy, lecz rzadko używany, typ elementów pozwalający na grupowanie kolumn i wierszy.

Wiersze można pogrupować korzystając ze znaczników thead (table heading), tbody (table body) oraz tfoot (table footer). Istnieje parę zasad ich używania. Mianowicie thead oraz tfoot mogą być użyte tylko raz w jednej tabeli, podczas gdy tbody dowolną ilość razy - przy czym każda grupa musi mieć choć jeden wiersz komórek (tr) w sobie.

  1. <table>
  2. <thead>
  3. <tr>
  4. <th>Kolumna</th>
  5. <th>Stereo</th>
  6. <th>Haj Fi</th>
  7. </tr>
  8. </thead>
  9. <tfoot>
  10. <tr>
  11. <td colspan="3">Opracował Ten'a'Ten</td>
  12. </tr>
  13. </tfoot>
  14. <tbody>
  15. <tr>
  16. <td>Dana</td>
  17. <td>Ojdana</td>
  18. <td>Ojdana dana</td>
  19. </tr>
  20. </tbody>
  21. </table>

Jak widać powyżej także umiejscowienie tfoot wydaje się dziwne, lecz tak właśnie ma być - znajduje się on zaraz pod thead, powyżej sekcji tbody. Wygląda to jednak standardowo - stopka tabeli umieszczona jest na dole.

Stosowanie takich sekcji pozwala na pogrupowanie części danych i ostylowanie ich przez CSS bądź na przykład umieszczenie identyfikatorów i odpowiednie nimi zarządzanie przez JavaScript.

Grupowanie kolumn

O wiele ciekawszym jednak grupowaniem wykazuje się colgroup oraz col. Elementy te swobodnie są umieszczone na początku tabelki, przed wierszami:

  1. <table>
  2. <colgroup span="1"></colgroup>
  3. <colgroup span="2"></colgroup>
  4. <tr>
  5. <th>Lp.</th>
  6. <td>Firma</td>
  7. <td>Data założenia</td>
  8. </tr>
  9. <tr>
  10. <td>1</td>
  11. <td>Google</td>
  12. <td>1998</td>
  13. </tr>
  14. <tr>
  15. <td>2</td>
  16. <td>Microsoft</td>
  17. <td>1975</td>
  18. </tr>
  19. <tr>
  20. <td>3</td>
  21. <td>Oracle</td>
  22. <td>1977</td>
  23. </tr>
  24. </table>

Mamy tutaj trzy kolumny. Są one podzielone na dwie sekcje za pomocą colgroup. Atrybut span mówi jak wiele kolumn ma znaleźć się w tej grupie. W przykładzie mamy jedną grupę na jedną kolumnę - span równy jest 1, choć można by go pominąć i napisać:

  1. <colgroup></colgroup>

Dalej występuje kolejny colgroup obejmujący dwie kolumny (span równy 2). Teraz najważniejsze - do czego to w ogóle się może przydać? W przykładowym kodzie umieszczono tylko trzy wiersze, ale gdyby ich były setki, jak to często ma miejsce. Jak w takiej długiej tabeli spowodować, że pierwsza kolumna przyjmie inny wygląd? Należy przyporządkować jakąś klasę (class) pierwszej komórce w każdym z setek wierszy.

Dysponując colgroup wystarczy dodać jej klasę i opisać wygląd przez CSS. Co więcej - w każdej grupie można odwołać się do dowolnej kolumny. Jeśli podzielono tabelę na 20 kolumn w jednej i 30 kolumn w drugiej grupie, to będąc zmuszonym zrobić coś z drugą i przedostatnią kolumną drugiej grupy możemy stracić godziny na dodawaniu kodu.

Ale rozwiązanie jest proste - powstał do tego element col. Przykładowe użycie z przypadku opisanego wyżej:

  1. <table>
  2. <colgroup span="20"></colgroup>
  3. <colgroup span="30">
  4. <col />
  5. <col id="secondCol" />
  6. <col span="26" />
  7. <col id="befLastCol" />
  8. <col />
  9. </colgroup>
  10. .
  11. </table>

Teraz korzystając z dwóch identyfikatorów mamy łatwy dostęp do komórek w tych kolumnach. Zmiana ilości kolumn spowoduje konieczność poprawienia tylko tych paru linijek kodu zamiast mozolnego walczenia z każdą komórką gdzieś daleko w głębi tabeli.

Zmiana wyglądu przez korzystanie z kolumn nie jest jednak usłana kwiatami. Właściwości CSS jakie można zaaplikować ograniczają się do:

Tak czy inaczej kolumnami i CSS można osiągnąć ciekawe, choć podstawowe efekty (przykład). Gdybyśmy potrzebowali bardziej zaawansowanego dostosowywania wyglądu kolumn, można wrócić do dawnego sposobu oznaczania komórek td jakąś klasą.

Wygląd tabeli

W przykładach powyżej wystrzegałem się używania atrybutów dla elementu table. Nie było więc border, nie było cellspacing, cellpadding. Nie używam ich, ponieważ za wygląd odpowiadają kaskadowe arkusze stylów. Lepiej wszystko mieć w jednym miejscu.

Teraz w jaki sposób doprowadzić przez CSS tabelkę do wyglądu osiąganego kiedyś przez atrybuty?

Border

Aplikowanie obramowania w tabelce może sprawić trochę kłopotów początkującym w dziedzinach standardów i styli. Opisanie elementu table właściwością border spowoduje pojawienie się prostokątnej ramki wokoło całej tabeli. Jak jednak stworzyć zwyczajną siatkę komórek?

Podpowiedź już padła - mianowicie należy ostylować komórki tabeli.

  1. td, th {
  2. border: 1px solid black;
  3. }

Tutaj czycha na nas pułapka. W ten sposób zapisany styl spowoduje pojawienie się dwupikselowej siatki. A to dlatego, że każda z komórek jest otoczona z czterech stron przez jednopikselową linię. Czas to zmienić:

  1. td, th {
  2. border-top: 1px solid black;
  3. border-left: 1px solid black;
  4. }

Teraz jest już lepiej, ale nadal to nie wszystko. Bo o ile siatka już jest ładna, to mimo wszystko niekompletna. Brakuje linii na dole tabeli i po prawej. Czemu? Chyba widać to od razu, ale może wyjaśnię - dla każdej komórki dodaliśmy obramowanie z góry (border-top) i z lewej (border-left). W ten sposób obramowanie z prawej strony i na dole było tworzone przez kolejną komórkę w rzędzie bądź kolumnie. Na krawędziach tabeli zabrakło komórek i zabrakło obramowania. Jak wyjść z tej sytuacji?

  1. table {
  2. border-right: 1px solid black;
  3. border-bottom: 1px solid black;
  4. }

Zaaplikować całej tabelce brakujące obramowanie na dole i po prawej. :)

Jest też inny sposób na obejście tego problemu. Wystarczy ustawić odpowiednią właściwość CSS - border-collapse: collapse - która powoduje że obramowanie tabelki się zapada. W ten sposób dwie sąsiadujące ze sobą linie 1px łączą się w jedną, także 1px.

Align

Wyrównanie do lewej, prawej bądź środka można aplikować przez text-align dla komórek tabelki.

  1. td {
  2. text-align: left;
  3. }

Cellspacing

Za odstępy między komórkami odpowiada właściwość CSS border-spacing dla elementu table. Działa ona w nowoczesnych przeglądarkach. Co jednak z Internet Explorerem? W większości przypadków potrzebujemy usunąć ten odstęp nadawany domyślnie przez przeglądarki. Wtedy możemy oszukać IE ustawiając border-collapse: collapse. Spowoduje to trochę inne potraktowanie tabelek przez silnik renderujący, a widzialnym efektem będzie usunięcie przerw.

Cellpadding

Dopełnienie w komórkach zwiększane, zmniejszane bądź likwidowane jest bardzo prosto. Jak nazwa wskazuje, należy zmienić właściwośc padding dla zwyczajnych komórek i komórek nagłówka:

  1. td, th {
  2. padding: 0;
  3. }

Podsumowanie

Opisane w artykule techniki tworzenia tabel nie są oczywiście niezbędne do ich najbardziej podstawowego zadania - pokazania tabelarycznych danych w stronie WWW. Nie są niezbędne, ale są bardzo wskazane - używając odpowiednich znaczników zapewnisz o wiele lepszą rozpoznawalność tabelki z wyłączonymi stylami. Używając rozszerzonych atrybutów - i przez to zwiększając dostępność - pozwolisz większej ilości osób z tych danych skorzystać. W obydwu przypadkach zyskujesz nie tylko Ty - dlatego daj się namówić i pisz tabele w nowoczesny i lepszy sposób już dzisiaj. :)

Piotr Petrus


Przykłady przedstawione w artykule


O autorze

Piotr Petrus

Piotr Petrus

Jest projektantem stron internetowych i twórcą artykułów o standardach sieciowych. Freelancer, miłośnik muzyki, pisze także na swoim blogu na tematy pokrywające się z jego pasjami. Uwielbia grzebać do rana w rzeczach, które wszystkim wokoło wydają się stratą czasu - on to jednak kocha.