Как правильно верстать HTML-таблицы
2026-02-21 06:24 Diff

#Руководства

  • 28 апр 2021
  • 0

Учимся верстать таблицы так, чтобы их верно понимали браузеры, поисковики и люди с ограниченными возможностями.

: colette / respawn entertainment, oculus

Frontend-разработчик, программист, дизайнер. Три года в разработке сайтов и приложений, около девяти — в дизайне. Был графдизайнером в языковой школе ILS и разработчиком в IT-компании IVIT. Сейчас преподаёт в Skillbox.

Практика показывает, что большинство разработчиков верстают таблицы HTML неверно — используют только теги строк и ячеек (<tr>, <td>).

Из этой статьи вы узнаете, как верстать таблицы с учётом не только синтаксиса, но и семантики — то есть обозначать нужные части таблицы тегами, которые отражают их содержание.

Семантический подход к вёрстке подразумевает использование HTML-тегов в соответствии с их семантикой (предназначением), а его суть заключается в верности выбора тегов и их взаимного расположения.

Семантические теги передают смысл (или обозначают важность) содержащегося в них контента.

Семантический подход — противоположность визуальному, при котором важно только то, как HTML-страница выглядит.

Почему семантика так важна

Она повышает доступность контента. Тогда его лучше понимают:

  • поисковые роботы (чем понятнее для них контент сайта, тем корректнее он представлен в поисковой выдаче и тем проще его найти пользователям);
  • браузеры и помощники для пользователей с ограниченными возможностями (например, программы, которые читают информацию с экрана, — скринридеры).

Семантически верно размеченный контент может выглядеть абсолютно так же, как и свёрстанный без учёта семантики. Это касается любых элементов на HTML-странице.

Так, можно использовать для всех них тег <div>, но он не обладает семантикой, никак не обозначает смысл своего содержимого. Поэтому мы применяем для заголовков теги H1… H6, для таблицы — <table>, <caption>, <thead>, <tbody>, <tfoot>, <th>. И так далее.

Рассмотрим, какие теги отвечают за вёрстку таблиц, когда и зачем нужен каждый.

Каждая таблица состоит из строк и ячеек, а задаётся тегом <table> — это контейнер для остальных тегов таблицы.

Тег <tr> образует контейнер для создания строки таблицы. Каждая ячейка в такой строке устанавливается с помощью тега <td> (хотя первая может быть задана и тегом <th>).

Важно понимать. Дочерними элементами строки могут быть только ячейки <td> (и заголовочная ячейка <th>). А сама строка <tr> дочерним элементом ячейки быть не может. Это ограничивает возможную вложенность тегов.

Рассмотрим пример:

Мы видим три строки (элементы <tr>). В каждой из строк по три ячейки (<td>). Представим это HTML-кодом:

<table> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> </table>

Ячейки можно объединять (растягивать по горизонтали и вертикали) с помощью специальных атрибутов. При этом поглощаемые ячейки задавать своими тегами уже не придётся.

Столбцы таблицы объединяются атрибутом colspan, а строки — атрибутом rowspan.

И тут важно не запутаться:

Атрибут colspan тегов <td> и <th> объединяет ячейки по горизонтали (то есть ячейки одной строки). Значение colspan указывает, сколько столбцов пересекает ячейка.

Атрибут rowspan тегов <td> и <th> объединяет ячейки по вертикали (то есть ячейки разных строк). Значение rowspan задаёт, через сколько строк проходит ячейка.

Рассмотрим пару примеров:

Вторая ячейка первой строки пересекает два столбца. То есть она растянулась по горизонтали и приняла в себя третью ячейку первой строки. Третья ячейка второй строки пересекает две строки, то есть растянулась по вертикали, заняв и третью ячейку третьей строки.

Поэтому третьи ячейки для первой и третьей строк задавать не нужно. Они уже поглощены другими. Теперь к коду:

<table> <tr> <td>1</td> <td colspan="2">2</td> </tr> <tr> <td>1</td> <td>2</td> <td rowspan="2">3</td> </tr> <tr> <td>1</td> <td>2</td> </tr> </table>

Ещё один пример:

Как такое сверстать:

<table> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <td>1</td> <td colspan="2" rowspan="2">2</td> </tr> <tr> <td>1</td> </tr> </table>

Здесь вторая ячейка второй строки занимает два столбца и две строки. Обратите внимание, что во второй строке нет третьей ячейки и в третьей строке нет второй и третьей ячеек. Теперь места этих ячеек занимает вторая ячейка второй строки.

Этот тег следует включать в любую таблицу. Где бы вы его ни разместили, его содержимое будет выведено перед таблицей. Изменить это можно с помощью свойства caption-side (значение top — для вывода до таблицы, и bottom — после).

Для единообразия и доступности тег заголовка размещают в самом начале — сразу после тега <table>.

Тег <caption> по умолчанию выравнивает своё содержимое по центру. Чтобы установить выравнивание по левому или правому краю, достаточно поменять значение свойства text-align.

Зачем нужен заголовок?

  • Чтобы пользователям было проще ориентироваться на странице — например, когда таблиц много.
  • Тег <caption> помогает людям с ограниченными возможностями. По заголовку они получают краткое представление о содержимом таблицы и решают, полезна ли она для них и стоит ли читать её целиком.
  • Этот тег влияет на оптимизацию, его любят поисковики.

Примечание. Если дизайнер не предусмотрел заголовок таблицы, то хороший разработчик придумает его, добавит в разметку и скроет через CSS. Это повысит доступность контента.

Даже скрытый заголовок всё равно доступен при навигации по странице с помощью клавиатуры. И речевой браузер для людей с ограниченными возможностями тоже понимает тег <caption> — читая текст в этом теге, он меняет интонацию, темп речи, повышает громкость голоса и тому подобное.

Структура таблиц очень похожа на структуру HTML-страницы. Только для страницы мы используем теги <header>, <main> и <footer>, а для таблицы — <thead>, <tbody> и <tfoot>.

Согласно стандарту HTML5, в таблице может быть только по одной секции thead и tfoot, а вот tbody — несколько.

Эти элементы полезны не только для доступности, но и для стилизации (как логичные точки добавления CSS к таблице).

Этим тегом задают заголовочную секцию таблицы. Чаще всего речь идёт о первой строке — содержащей заголовки столбцов.

Браузер и поисковики считают эту часть заголовочным колонтитулом таблицы. Например, при печати колонтитулы таблицы будут на каждой напечатанной странице — и благодаря такой шапке вы не забудете, что значат данные каждого столбца.

В <thead> для ячеек используют тег <th>. Контент в ячейке th браузер выравнивает по центру, а текст к тому же отображает жирным шрифтом.

Например:

Сaption

<table> <caption>Caption</caption> <thead> <tr> <th>th</th> <th colspan="4">th</th> </tr> </thead> <tbody> <tr> <td>td</td> <td>td</td> <td>td</td> <td>td</td> <td>td</td> </tr> <tr> <td>td</td> <td>td</td> <td>td</td> <td>td</td> <td>td</td> </tr> </tbody> </table>

Из примера видно, что первая строка объединяет две ячейки <th>. Первая ячейка первой строки — это заголовок для других ячеек первого столбца, а вторая ячейка первой строки — это заголовок четырёх оставшихся столбцов.

Тег <th> задаёт особые ячейки, с которых начинаются строки или столбцы. В такой ячейке обычно хранится атрибут для всех данных строки или столбца.

Как мы и говорили выше, к содержимому таких ячеек применяется определённый стиль: по умолчанию это выделение жирным шрифтом и выравнивание по центру ячейки.

Благодаря заголовочным ячейкам таблица выглядит лучше, а искать данные в ней становится проще.

Важно. Не применяйте <th> для визуального форматирования — только для выделения ячейки-заголовка. Этот принцип касается всех элементов разметки, которые обладают семантикой.

Тег <th> даёт ещё одно преимущество: вместе с атрибутом scope он связывает каждый заголовок со всеми данными строки или столбца. То есть добавляет к интуитивной, визуально считываемой связи такую, которую понимают и программы.

К тегу <th> и атрибуту scope мы вернёмся ближе к концу статьи, где подробнее поговорим о доступности таблиц для пользователей с ограниченными возможностями.

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

Тег <tbody> семантически важен: браузер, поисковые роботы и помощники для людей с ограниченными возможностями благодаря ему понимают, где находится основное содержимое таблицы.

Тело таблицы располагается после заголовка <caption> и шапки <thead>.

Пример:

МесяцДни неделиОплата(тыс. р.)ЯнварьПонедельник50Вторник40Среда35Четверг40Пятница15Суббота60Воскресенье30ФевральПонедельник20Вторник25Среда15Четверг70Пятница77Суббота63Воскресенье30

Здесь нет заголовка <caption>, поэтому нужно его придумать и скрыть с помощью CSS (для доступности веб-содержимого).

Данные основной части таблицы надо сгруппировать по смыслу. У нас сначала идёт январь, затем февраль. Значит, для данных каждого месяца логично использовать свой <tbody>:

  • в первом <tbody> будут январские строки;
  • во втором <tbody> — февральские.

Секция <tfoot> используется для группировки содержимого нижней части таблицы.

Семантически это итог таблицы (например, результат подсчёта сумм по столбцам).

А ещё это нижний колонтитул таблицы, браузер выводит его после <tbody>, а при печати таблицы содержимое <tfoot> может быть как на каждой напечатанной странице, так и только на последней (это зависит от браузера).

Важно. Чтобы предотвратить проблемы с доступностью (клавиатурная навигация и специальные возможности), размещать <tfoot> следует после <tbody>.

Для ячеек в секции <tfoot> следует использовать тег <td>.

Пример:

Таблица чисел

НечётноеЧётное123456Вы узнали, что такое чётные и нечётные числа<table> <caption>Таблицa чисел</caption> <thead> <tr> <th>Нечётное</th> <th>Чётное</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>2</td> </tr> <tr> <td>3</td> <td>4</td> </tr> <tr> <td>5</td> <td>6</td> </tr> </tbody> <tfoot> <tr> <td colspan="2"> Вы узнали, что такое чётные и нечётные числа </td> </tr> </tfoot> </table>

Последняя строка нашего примера — это по смыслу итог таблицы. Поэтому её вполне уместно обернуть тегом <tfoot>, превратив в нижний колонтитул.

Теги <thead> и <tfoot> нужны не всегда. Бывают таблицы без шапки и подвала.

Если нет смысла группировать основную часть таблицы, то можно обойтись и без тега <tbody>, но мы рекомендуем не делать так. Тег даёт больше контроля над структурой таблицы и стилизацией, а также приучает действовать последовательно.

К тому же браузер всё равно подставит этот тег сам, а всегда полагаться на браузеры — значит оставить место для возможных ошибок.

Пример:

1Мавзалеев И. В.10.09.19922Киреева А. Ю.02.05.19963Корнеев И. Ю.09.10.19904Тресков В. А.25.03.19935Ибрагимов А. Е.15.10.19946Борисенко Д. С.10.10.1991

В таблице выше шесть строк, каждая из которых содержит три ячейки. Здесь нет важных для смысла признаков, по которым можно сгруппировать содержимое таблицы. Поэтому будет достаточно тега <caption> (придумаем его и скроем) и тега <tbody>, а вот теги <thead> и <tfoot> можно опустить.

C помощью тега <col> удобно стилизовать столбцы таблицы через CSS (не приходится писать классы для каждой ячейки в разных строках). Это крутая фишка для любого разработчика.

Как это работает:

Caption

<table class="table"> <caption>Caption</caption> <col class="col-first"> <col> <col> <thead> <tr> <th>th</th> <th colspan="2">th</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <td>1</td> <td>2</td> <td>3</td> </tr> </tbody> </table>

У нас три ячейки и, следовательно, три столбца. Поэтому мы используем три тега <col>.

Для группировки тегов <col> применяют специальный тег <colgroup>:

<colgroup> <col class="col-first"> <col> <col> </colgroup>

<colgroup> позволяет задать стиль сразу для группы столбцов, а тег <col> внутри <colgroup> — переопределить его для отдельных столбцов в группе.

Располагать теги <colgroup>, <col> нужно перед тегами <thead>, <tbody>, <tfoot>, а если у таблицы есть тег <caption>, то после него.

У тега <col> есть атрибут span, который распространяет стиль на несколько столбцов.

Например:

Caption

<table class="table"> <caption>Caption</caption> <colgroup> <col> <col span="2" class="col-second"> <col> </colgroup> <thead> <tr> <th>th</th> <th>th</th> <th>th</th> <th>th</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>2</td> <td>3</td> <td>4</td> </tr> </tbody> </table>

Первый тег <col> — это первый столбец, а второй тег <col> — второй, но из-за атрибута span, в котором мы указали значение "2", его стиль распространяется и на третий.

Это удобно, когда нужно одинаково стилизовать несколько столбцов. Например, чтобы не создавать много тегов <col> с одними и теми же классами, мы используем атрибут span. Этот атрибут работает и для тега <colgroup>.

Когда таблица хорошо структурирована, достаточно беглого взгляда, чтобы понять, какие где данные: мигом возникают визуальные ассоциации между основной информацией в таблице и заголовками её колонок и/или строк.

Но что, если наши пользователи не могут провести такую визуальную параллель. Например, они слабовидящие. Как им прочитать сложную таблицу?

Люди с ослабленным зрением часто применяют скринридеры — программы, которые читают для них веб-страницы. С обычным текстом скринридер справляется хорошо, но интерпретировать сложную таблицу для него проблема.

Поэтому разработчики должны позаботиться об этом и дополнить визуальные ассоциации в таблице программными, которые скринридер сможет понять.

Чаще всего это делают с помощью тега <th> и атрибута scope, который сообщает скринридеру, какие ячейки точно являются заголовками — например, заголовок строки, в которой программа находится, или же заголовок столбца.

Благодаря им все пользователи могут интерпретировать таблицу так же, как и зрячие люди.

Пример

Вернёмся к нашей таблице чётности чисел:

Таблица чисел

НечётноеЧётное123456Вы узнали, что такое чётные и нечётные числа

Чтобы однозначно указать заголовки столбцов, делаем вот так:

<table> <caption>Таблицa чисел</caption> <thead> <tr> <th scope="col">Нечётное</th> <th scope="col">Чётное</th> </tr> </thead> <tbody> <!--HTML-код--> </tbody> <tfoot> <!--HTML-код--> </tfoot> </table>

И у каждой строки тоже можно определить заголовок (если в таблице есть не только заголовки столбцов). Слегка изменим для этого наш пример:

Таблица чисел

Пара №НечётноеЧётное112234356Вы узнали, что такое чётные и нечётные числа

И снова к HTML:

<table> <caption>Таблицa чисел</caption> <thead> <tr> <th scope="col">Пара №</th> <th scope="col">Нечётное</th> <th scope="col">Чётное</th> </tr> </thead> <tbody> <tr> <th scope="row">1</th> <td>1</td> <td>2</td> </tr> <tr> <th scope="row">2</th> <td>3</td> <td>4</td> </tr> <tr> <th scope="row">3</th> <td>5</td> <td>6</td> </tr> </tbody> <tfoot> <tr> <td colspan="3"> Вы узнали, что такое чётные и нечётные числа </td> </tr> </tfoot> </table>

Скринридер распознаёт такую семантическую разметку и позволяет пользователям прочесть весь столбец или строку целиком.

У атрибута scope есть ещё два значения — colgroup и rowgroup. Они используются для таблиц с двумя и более уровнями заголовков (заголовки, которые группируют подзаголовки).

Так заголовок верхнего уровня получает scope="colgroup", а у его подзаголовков scope="col", и аналогично для строк.

  • Таблица состоит из строк <tr> и ячеек (<td> и <th>). Дочерними элементами строки <tr> могут быть только ячейки, но не наоборот.
  • Таблице нужен заголовок <caption>. Он увеличивает доступность веб-содержимого. Если дизайнер не учёл этого, верстальщик сам придумывает заголовок и скрывает его с помощью CSS.
  • За логическое структурирование таблицы, помимо заголовка <caption>, отвечают теги <thead>, <tbody> и <tfoot>. Также они полезны при стилизации секций таблицы.
  • Внутри <thead> ячееки задают тегом <th> (он семантический), внутри <tfoot> — <td>, а внутри <tbody> допустимы оба.
  • Для стилизации столбцов в таблице применяют тег <col>.

Заботьтесь обо всех пользователях — верстайте таблицы семантически верно.

Бесплатный курс по Python ➞
Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу