Tablica danych w HTML to najprostszy sposób na pokazanie uporządkowanych informacji w wierszach i kolumnach. Bez względu na to, czy chodzi o cennik, plan zajęć, czy zestawienie wyników – tabela HTML daje pełną kontrolę nad strukturą. Poniżej konkretny przewodnik: od zera do praktycznych przykładów, które można od razu skopiować do projektu. Kod pokazuje zarówno podstawy, jak i elementy, które faktycznie przydają się w codziennej pracy. Wszystko w wersji do samodzielnego użycia, bez zbędnej teorii.
Podstawowa struktura tabeli w HTML
Tabela w HTML składa się z kilku podstawowych znaczników: <table>, <tr>, <td> oraz <th>. W praktyce wygląda to jak prosta hierarchia: tabela → wiersze → komórki.
<table>
<tr>
<th>Kolumna 1</th>
<th>Kolumna 2</th>
</tr>
<tr>
<td>Wartość 1</td>
<td>Wartość 2</td>
</tr>
</table>
Znaczniki w skrócie:
- <table> – kontener całej tabeli.
- <tr> (table row) – pojedynczy wiersz tabeli.
- <td> (table data) – zwykła komórka z danymi.
- <th> (table header) – komórka nagłówkowa, domyślnie pogrubiona i wyśrodkowana.
Tekst w <th> jest traktowany przez czytniki ekranu jako nagłówek kolumny lub wiersza, co mocno poprawia dostępność tabeli.
Na początek wystarczy powyższy szkielet. Stylowanie (ramki, odstępy, kolory) warto dodać osobno, zamiast korzystać z przestarzałych atrybutów typu border bezpośrednio w znaczniku.
Tworzenie prostej tabeli krok po kroku
Najszybciej opanować tabele, tworząc konkretny przykład. Poniżej prosty cennik usług z trzema kolumnami i kilkoma wierszami.
- Najpierw struktura HTML dokumentu (w wersji minimalnej):
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Przykładowa tabela</title>
</head>
<body>
<!-- Tabela pojawi się tutaj -->
</body>
</html>
- Wewnątrz <body> dodana zostaje tabela z nagłówkiem i trzema wierszami danych:
<table>
<tr>
<th>Usługa</th>
<th>Czas trwania</th>
<th>Cena</th>
</tr>
<tr>
<td>Konsultacja online</td>
<td>30 minut</td>
<td>150 zł</td>
</tr>
<tr>
<td>Audyt strony WWW</td>
<td>2 godziny</td>
<td>400 zł</td>
</tr>
<tr>
<td>Szkolenie indywidualne</td>
<td>3 godziny</td>
<td>700 zł</td>
</tr>
</table>
Taki kod da się od razu otworzyć w przeglądarce. Tabela będzie wyglądała surowo (bez ramek i kolorów), ale struktura jest poprawna i czytelna. Na tym etapie ważne jest, by każdy wiersz <tr> miał tę samą liczbę komórek – przynajmniej dopóki nie pojawi się potrzeba łączenia komórek.
Nagłówki, podpis i sekcje tabeli
Przy większych tabelach (np. raporty, statystyki) warto uporządkować strukturę, korzystając z <thead>, <tbody>, <tfoot> i <caption>. Pozwala to zarówno na lepszą semantykę, jak i łatwiejsze stylowanie.
Nagłówki kolumn i wierszy
Nagłówki nie muszą pojawiać się tylko w pierwszym wierszu. Często stosuje się nagłówki w pierwszej kolumnie, opisujące całe wiersze. Dzięki temu dane są czytelniejsze, a użytkownicy korzystający z czytników ekranu otrzymują pełne informacje kontekstowe.
<table>
<thead>
<tr>
<th>Dzień</th>
<th>Godzina</th>
<th>Zajęcia</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Poniedziałek</th>
<td>18:00</td>
<td>Yoga</td>
</tr>
<tr>
<th scope="row">Środa</th>
<td>19:30</td>
<td>Trening siłowy</td>
</tr>
</tbody>
</table>
Atrybut scope=”row” jasno określa, że dany nagłówek dotyczy całego wiersza. Analogicznie można użyć scope=”col” przy nagłówkach kolumn (w <thead>), co ułatwia pracę technologiom asystującym.
Podpis tabeli i sekcje <thead> / <tbody> / <tfoot>
Znacznik <caption> dodaje podpis do tabeli, który wyświetla się domyślnie nad nią. To lepsze rozwiązanie niż dodawanie tytułu tabeli zwykłym tekstem przed nią, bo podpis jest powiązany semantycznie z tabelą.
<table>
<caption>Plan zajęć na tydzień</caption>
<thead>
<tr>
<th>Dzień</th>
<th>Godzina</th>
<th>Zajęcia</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Poniedziałek</th>
<td>18:00</td>
<td>Yoga</td>
</tr>
<tr>
<th scope="row">Środa</th>
<td>19:30</td>
<td>Trening siłowy</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Obowiązuje od 01.03.2026 r.</td>
</tr>
</tfoot>
</table>
Sekcja <tfoot> dobrze sprawdza się przy tabelach z podsumowaniami (np. suma wartości, stopka raportu). Nawet jeśli wizualnie ma znaleźć się na dole, w kodzie HTML często umieszcza się ją przed <tbody>, żeby przeglądarka mogła szybciej wyrenderować strukturę – ale nie jest to obowiązkowe.
Sekcje <thead>, <tbody>, <tfoot> ułatwiają także stylowanie: można nadać inny kolor tła nagłówkom, inny wierszom z danymi i inny podsumowaniu, bez dodatkowych klas.
Stylowanie tabeli: obramowanie, odstępy i czytelność
Surowa tabela HTML bez stylów jest mało czytelna. W praktycznym projekcie od razu warto dorzucić podstawowe style: ramki, odstępy, wyrównanie. Najlepiej zrobić to w CSS, a nie w atrybutach HTML.
Obramowanie i siatka
Najprostszy wariant, który wygląda dobrze w większości projektów, to cienka, szara siatka i zlane obramowania. Poniżej kompletny przykład z prostym stylem.
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Tabela stylowana</title>
<style>
table {
width: 100%;
border-collapse: collapse; /* zlanie obramowań */
}
th, td {
border: 1px solid #ccc;
padding: 8px 12px;
text-align: left;
}
thead th {
background-color: #f5f5f5;
}
tbody tr:nth-child(even) {
background-color: #fafafa; /* pasiaste wiersze */
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>Produkt</th>
<th>Ilość</th>
<th>Cena</th>
</tr>
</thead>
<tbody>
<tr>
<td>Klawiatura</td>
<td>2</td>
<td>120 zł</td>
</tr>
<tr>
<td>Mysz</td>
<td>1</td>
<td>60 zł</td>
</tr>
</tbody>
</table>
</body>
</html>
Kluczowy parametr to border-collapse: collapse;. Bez niego każda komórka ma własne obramowanie i tabela wygląda „podwójnie” obrysowana. Przy większej ilości danych pasiaste wiersze (nth-child(even)) znacząco poprawiają czytelność.
Odstępy, wyrównanie i formatowanie liczb
Odstępy w komórkach ustawia się przez padding. Mała różnica (np. 8–12 px) potrafi zdecydować o tym, czy tabela wygląda na dopracowaną, czy ściśniętą. Warto też zadbać o wyrównanie danych liczbowych do prawej strony lub do środka, szczególnie przy cenach czy ilościach.
<style>
td.cena {
text-align: right;
font-weight: bold;
white-space: nowrap; /* zapobiega łamaniu 1200 zł na dwie linie */
}
td.liczba {
text-align: right;
}
</style>
<table>
<tr>
<th>Produkt</th>
<th>Ilość</th>
<th>Cena</th>
</tr>
<tr>
<td>Monitor</td>
<td class="liczba">3</td>
<td class="cena">1200 zł</td>
</tr>
</table>
W praktycznych tabelach warto rozdzielać klasy według rodzaju danych (np. .cena, .liczba, .procent), zamiast nadawać style na podstawie pozycji kolumny. Dzięki temu zmiana kolejności kolumn nie wymaga poprawiania CSS.
Łączenie komórek: colspan i rowspan
W bardziej rozbudowanych tabelach często zachodzi potrzeba łączenia kilku kolumn lub wierszy w jedną komórkę. Służą do tego atrybuty colspan (poziomo) i rowspan (pionowo).
Przykład prostego nagłówka, który rozciąga się na dwie kolumny:
<table>
<tr>
<th rowspan="2">Miesiąc</th>
<th colspan="2">Sprzedaż</th>
</tr>
<tr>
<th>Online</th>
<th>Stacjonarna</th>
</tr>
<tr>
<th scope="row">Styczeń</th>
<td>1200 zł</td>
<td>800 zł</td>
</tr>
</table>
W pierwszym wierszu nagłówkowym:
- rowspan=”2″ przy „Miesiąc” łączy komórkę w pionie na dwa wiersze,
- colspan=”2″ przy „Sprzedaż” łączy dwie kolumny w jedną szeroką komórkę.
Najczęstszy błąd przy korzystaniu z colspan i rowspan to gubienie liczby komórek w kolejnych wierszach. Przeglądarka spróbuje to naprawić po swojemu, ale efekt wizualny bywa mało przewidywalny. Najbezpieczniej po każdym większym łączeniu komórek chwilowo dodać obramowanie do tabeli i sprawdzić, czy siatka się zgadza.
Przy tabelach z dużą liczbą połączonych komórek warto naszkicować układ na kartce lub w prostym edytorze graficznym, zanim zacznie się pisać HTML – oszczędza to sporo czasu na późniejsze poprawki.
Responsywne tabele w praktyce
Klasyczna tabela z wieloma kolumnami źle znosi małe ekrany. Zamiast wciskać ją na siłę w szerokość telefonu, lepiej zastosować prosty trik: poziome przewijanie wewnątrz kontenera. To najszybsze i najbezpieczniejsze rozwiązanie dla tabel z dużą ilością danych.
Przewijana tabela na małych ekranach
Wariant bazowy polega na opakowaniu tabeli w <div> z włączonym przewijaniem w poziomie. Nie zmienia to struktury danych, więc tabela nadal jest poprawna semantycznie.
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Responsywna tabela</title>
<style>
.tabela-wrap {
width: 100%;
overflow-x: auto;
}
table {
border-collapse: collapse;
min-width: 600px; /* zapobiega zgnieceniu kolumn */
}
th, td {
border: 1px solid #ddd;
padding: 8px;
white-space: nowrap;
}
thead th {
background: #f0f0f0;
}
</style>
</head>
<body>
<div class="tabela-wrap">
<table>
<thead>
<tr>
<th>Data</th>
<th>Klient</th>
<th>Projekt</th>
<th>Godziny</th>
<th>Stawka</th>
<th>Kwota</th>
</tr>
</thead>
<tbody>
<tr>
<td>01.03.2026</td>
<td>ABC Sp. z o.o.</td>
<td>Strona WWW</td>
<td>6</td>
<td>200 zł</td>
<td>1200 zł</td>
</tr>
<tr>
<td>02.03.2026</td>
<td>XYZ S.A.</td>
<td>Aplikacja</td>
<td>4</td>
<td>250 zł</td>
<td>1000 zł</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Na dużych ekranach tabela zachowuje się normalnie, na małych pojawia się poziomy pasek przewijania tylko dla tego jednego elementu. Rozwiązanie jest proste, nie wymaga JavaScriptu i działa dobrze nawet przy dużych zestawieniach.
Bardziej zaawansowane podejścia (przekształcanie tabel w „karty” na mobile, ukrywanie mniej ważnych kolumn) wymagają już indywidualnego projektowania layoutu i często JavaScriptu. Do większości praktycznych zastosowań w zupełności wystarcza jednak poziome przewijanie plus dobrze zaplanowane nagłówki.
