Tagi HTML: tbody

8 min. czytania

Witaj na moim blogu poświęconym programowaniu w HTML, CSS i JavaScript! Dziś zanurzymy się w szczegóły elementu <tbody>, który jest kluczowym elementem struktury tabel w HTML. Jego świadome użycie poprawia semantykę, ułatwia stylizację i usprawnia zachowanie tabel w druku oraz przy dużych zbiorach danych.

<tbody> reprezentuje główną treść tabeli, grupując wiersze danych w czytelną sekcję. W połączeniu z <thead> (nagłówek) i <tfoot> (stopka) tworzy kompletną, semantyczną strukturę tabeli.

Czym dokładnie jest <tbody> i dlaczego warto go używać?

Element <tbody> (table body) służy do grupowania wierszy <tr> zawierających główne dane tabeli. Jeśli umieścisz wiersze bezpośrednio wewnątrz <table>, przeglądarka i tak utworzy domyślną sekcję <tbody> i przeniesie do niej wiersze. Jawne stosowanie <tbody> daje jednak pełną kontrolę nad selektorami CSS i logiką JS.

Najważniejsze korzyści z używania <tbody> są następujące:

  • semantyka – przeglądarki, wyszukiwarki i czytniki ekranu lepiej rozumieją strukturę tabeli;
  • stylizacja CSS – możesz niezależnie formatować ciało tabeli (np. tła, czcionki, efekty hover) bez modyfikowania nagłówków;
  • funkcjonalność – łatwiej uzyskać przewijanie tylko ciała tabeli, powtarzanie nagłówków przy druku czy sortowanie danych;
  • elastyczność – możesz mieć wiele sekcji <tbody>, aby tematycznie grupować wiersze.

Zgodnie ze specyfikacją HTML, <tbody> jest potomkiem <table> (po <caption>, <colgroup> i opcjonalnym <thead>). Wiersze <tr> powinny znajdować się w sekcjach <thead>, <tbody> lub <tfoot>; w przeciwnym razie przeglądarka utworzy sekcję <tbody> implicite.

Elementy potomne – dowolna liczba <tr> oraz elementy wspierające skrypty.
Interfejs DOMHTMLTableSectionElement (np. document.querySelector('tbody').insertRow()).

<tbody> nie ma atrybutów obowiązkowych; obsługuje atrybuty globalne (np. id, class) i zdarzeniowe (np. onclick). Atrybuty prezentacyjne (np. align, valign) są przestarzałe – używaj CSS.

Podstawowy przykład użycia <tbody>

Oto prosta tabela z pełną, semantyczną strukturą: nagłówek w <thead>, dane w <tbody>, podsumowanie w <tfoot>:

<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Przykład tabeli z tbody</title>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
thead { background-color: #f2f2f2; }
tbody { background-color: #fafafa; }
tfoot { background-color: #e9e9e9; font-weight: bold; }
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>Miesiąc</th>
<th>Oszczędności</th>
</tr>
</thead>
<tbody>
<tr>
<td>Styczeń</td>
<td>100 zł</td>
</tr>
<tr>
<td>Luty</td>
<td>80 zł</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Suma</td>
<td>180 zł</td>
</tr>
</tfoot>
</table>
</body>
</html>

Efekt – czytelna tabela z wyróżnionym nagłówkiem oraz odmiennym tłem ciała i stopki.

Zaawansowana stylizacja <tbody> z CSS

Domyślnie <thead>, <tbody> i <tfoot> nie zmieniają układu, ale CSS daje pełną kontrolę. Oto wybrane techniki:

1. Wyrównanie treści w <tbody>

Aby wyrównać zawartość komórek w poziomie i pionie, użyj:

tbody {
text-align: right; /* wyrównanie poziome do prawej */
vertical-align: bottom; /* wyrównanie pionowe do dołu */
}

W tabeli z wysokimi wierszami (np. height: 100px) dane będą „przyklejone” do dołu komórek.

2. Efekty hover tylko w ciele tabeli

Jeśli chcesz, by efekt najechania działał wyłącznie na wiersze z danymi, użyj selektora ograniczonego do <tbody>:

tbody tr:hover {
background-color: #f5f5f5;
cursor: pointer;
}

To pozwala zachować nagłówek w niezmienionej formie.

3. Przewijalne ciało tabeli ze „sticky” nagłówkiem

Dla bardzo długich tabel możesz ustawić przewijanie tylko dla sekcji danych oraz przyklejony nagłówek:

table {
width: 100%;
border-collapse: collapse;
}
thead th {
position: sticky;
top: 0;
background: #f2f2f2;
z-index: 10;
}
tbody {
display: block;
height: 300px; /* stała wysokość ciała tabeli */
overflow-y: auto; /* przewijanie pionowe sekcji danych */
}
thead, tfoot {
display: table;
width: 100%;
table-layout: fixed; /* spójne szerokości kolumn */
}

Uwaga – ta technika bywa wrażliwa na różnice szerokości kolumn; w praktyce często wymaga dodatkowego JS do ich synchronizacji.

<tbody> w praktyce: przykład z danymi sprzedażowymi

Poniżej rozbudowana tabela zakupów z podsumowaniem w stopce i dwoma sekcjami <tbody> (owoce i pieczywo):

<table class="zakupy">
<thead>
<tr>
<th>Produkt</th>
<th>Ilość</th>
<th>Cena (PLN)</th>
<th>Wartość (PLN)</th>
</tr>
</thead>

<tbody class="owoce">
<tr><td>Jabłka</td><td>2 kg</td><td>3.50</td><td>7.00</td></tr>
<tr><td>Mleko</td><td>3 l</td><td>2.80</td><td>8.40</td></tr>
</tbody>

<tbody class="pieczywo">
<tr><td>Chleb</td><td>1 szt.</td><td>4.20</td><td>4.20</td></tr>
</tbody>

<tfoot>
<tr>
<td colspan="3">Suma:</td>
<td>19.60 PLN</td>
</tr>
</tfoot>
</table>

Minimalne style ułatwiają czytelność sekcji w tym przykładzie:

.zakupy {
width: 100%;
border-collapse: collapse;
}
.zakupy th, .zakupy td {
border: 1px solid #ccc;
padding: 12px;
}
.owoce { background-color: #e8f5e8; }
.pieczywo { background-color: #f0f8f0; }
tfoot { background-color: #ddd; font-weight: bold; }

Wiele sekcji <tbody> ułatwia różnicowanie stylów oraz operacje na grupach danych (filtrowanie, ukrywanie, sortowanie).

Integracja z JavaScript: dynamiczne manipulacje <tbody>

Aby dynamicznie dodać wiersz do sekcji danych, możesz użyć interfejsu HTMLTableSectionElement:

const tbody = document.querySelector('tbody');
const nowyWiersz = tbody.insertRow(); // dodaje pusty <tr>
nowyWiersz.insertCell(0).textContent = 'Marzec';
nowyWiersz.insertCell(1).textContent = '120 zł';

Prosty przykład sortowania rosnąco po pierwszej kolumnie (po kliknięciu w pierwszy nagłówek):

const tbody = document.querySelector('tbody');
document.querySelector('thead th').addEventListener('click', () => {
const rows = Array.from(tbody.rows);
rows.sort((a, b) =>
a.cells[0].textContent.localeCompare(b.cells[0].textContent, 'pl')
);
rows.forEach(row => tbody.appendChild(row));
});

Oddzielenie danych w <tbody> upraszcza wybieranie wierszy w JS i minimalizuje ryzyko przypadkowych zmian w nagłówkach.

Najczęstsze błędy i dobre praktyki

Oto praktyki i pułapki, na które warto zwrócić uwagę podczas pracy z tabelami:

  • błąd – umieszczanie <tfoot> po <tbody>; w starszych silnikach przeglądarek powtarzanie stopki przy druku działało pewniej, gdy <tfoot> znajdował się przed <tbody>;
  • błąd – brak jawnego <tbody>; przeglądarka doda go implicite, ale tracisz precyzyjną semantykę i łatwe selektory CSS/JS;
  • praktyka – w większych tabelach (np. ponad 10 wierszy) zawsze wydzielaj <thead>, <tbody> i (opcjonalnie) <tfoot>;
  • praktyka – testuj z czytnikami ekranu (NVDA, JAWS), bo poprawna semantyka realnie zwiększa dostępność;
  • dla responsywności – stosuj media queries, np. @media (max-width: 600px) { thead { display: none; } tbody tr { display: block; } }.

Podsumowując korzyści w tabeli porównawczej

Poniższe zestawienie pokazuje różnice między tabelą bez jawnego <tbody> a tabelą z poprawnie zdefiniowanym <tbody>:

Aspekt Bez <tbody> Z <tbody>
Semantyka Słaba (implikowana) Doskonała
Stylizacja CSS Ograniczona selekcja Precyzyjna (np. tbody tr:hover)
Druk/przewijanie Mała kontrola Lepsza kontrola (powtarzany nagłówek)
Manipulacja w JS Trudniejsza Prosta (np. insertRow())

Element <tbody> to nie ozdoba – to fundament profesjonalnych, dostępnych i łatwych w utrzymaniu tabel w HTML5.