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

Таблицы

Как устроены таблицы в HTML и как их правильно верстать.

Время чтения: 15 мин

Кратко

Секция статьи "Кратко"

Иногда для простоты восприятия контент нужно оформить в виде таблицы.
Таблица состоит из строк и столбцов и предназначена для структурирования данных. Часто в таблицах размещают однотипные данные. Пример таблицы из школьных лет — классный журнал. Каждая строка это ученик. Колонки — даты. Напротив каждой фамилии можно проставить оценку за урок, прошедший в конкретную дату.

В HTML для создания таблиц существует набор семантических тегов:

  • <table>
  • <thead>
  • <tbody>
  • <tfoot>
  • <th>
  • <tr>
  • <td>

Пример

Секция статьи "Пример"

Создадим таблицу с первыми тремя местами в топ-250 лучших фильмов:

        
          
          <table>  <thead>    <tr>      <th>Место</th>      <th>Оценка</th>      <th>Название фильма</th>      <th>Год выхода</th>    </tr>  </thead>  <tbody>    <tr>      <td>1</td>      <td>9.1</td>      <td>Зелёная миля</td>      <td>1999</td>    </tr>    <tr>      <td>2</td>      <td>9.1</td>      <td>Побег из Шоушенка</td>      <td>1994</td>    </tr>    <tr>      <td>3</td>      <td>8.6</td>      <td>Властелин колец: Возвращение Короля</td>      <td>2003</td>    </tr>  </tbody></table>
          <table>
  <thead>
    <tr>
      <th>Место</th>
      <th>Оценка</th>
      <th>Название фильма</th>
      <th>Год выхода</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>9.1</td>
      <td>Зелёная миля</td>
      <td>1999</td>
    </tr>
    <tr>
      <td>2</td>
      <td>9.1</td>
      <td>Побег из Шоушенка</td>
      <td>1994</td>
    </tr>
    <tr>
      <td>3</td>
      <td>8.6</td>
      <td>Властелин колец: Возвращение Короля</td>
      <td>2003</td>
    </tr>
  </tbody>
</table>

        
        
          
        
      
Открыть демо в новой вкладке

Структурные теги

Секция статьи "Структурные теги"

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

<table>

Секция статьи "
"

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

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

        
          
          <table></table>
          <table>

</table>

        
        
          
        
      

<tr>

Секция статьи ""

Любая таблица в первую очередь состоит из строк. Чтобы в таблице появились строки, используйте парный тег <tr>. Сколько нужно строк — столько раз нужно написать <tr> внутри <table>.

Пока добавим три строчки в таблицу:

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

        
        
          
        
      

«tr» расшифровывается как «table row» и переводится «ряд таблицы».

<td>

Секция статьи ""

Все теги до этого только создавали структуру, но данных мы пока никуда не добавляли. Чтобы создать ячейку под данные, нужен парный тег <td>. Пишем столько <td> внутри <tr>, сколько нужно ячеек таблицы.

Ячейки формируют из себя столбцы. В HTML нет специального тега для столбцов.

Ячейки теоретически могут существовать и без <tr>. Они будут выстраиваться в строку. Чтобы новые ячейки встали в новую строку, мы как раз и используем <tr>.

        
          
          <table>  <tr>    <td>iPhone 12 Pro</td>    <td>$999</td>  </tr>  <tr>    <td>iPhone 12</td>    <td>$799</td>  </tr>  <tr>    <td>iPhone 12 mini</td>    <td>$699</td>  </tr></table>
          <table>
  <tr>
    <td>iPhone 12 Pro</td>
    <td>$999</td>
  </tr>
  <tr>
    <td>iPhone 12</td>
    <td>$799</td>
  </tr>
  <tr>
    <td>iPhone 12 mini</td>
    <td>$699</td>
  </tr>
</table>

        
        
          
        
      

«td» расшифровывается как «table data» и переводится «данные таблицы».

Теперь в нашей таблице 3 строки. В каждой строке по две ячейки. Из этих ячеек складывается два столбца.

Открыть демо в новой вкладке

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

В принципе, можно использовать уже знакомые нам <tr> и <td>:

        
          
          <table>  <tr>    <td>Модель</td>    <td>Цена</td>  </tr>  <tr>    <td>iPhone 12 Pro</td>    <td>$999</td>  </tr>  <tr>    <td>iPhone 12</td>    <td>$799</td>  </tr>  <tr>    <td>iPhone 12 mini</td>    <td>$699</td>  </tr></table>
          <table>
  <tr>
    <td>Модель</td>
    <td>Цена</td>
  </tr>
  <tr>
    <td>iPhone 12 Pro</td>
    <td>$999</td>
  </tr>
  <tr>
    <td>iPhone 12</td>
    <td>$799</td>
  </tr>
  <tr>
    <td>iPhone 12 mini</td>
    <td>$699</td>
  </tr>
</table>

        
        
          
        
      

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

Открыть демо в новой вкладке

<th>

Секция статьи ""

Специально для заголовков ячеек или строк есть тег <th>. Обернём в этот парный тег заголовки:

        
          
          <table>  <tr>    <th>Модель</th>    <th>Цена</th>  </tr>  <tr>    <td>iPhone 12 Pro</td>    <td>$999</td>  </tr>  <tr>    <td>iPhone 12</td>    <td>$799</td>  </tr>  <tr>    <td>iPhone 12 mini</td>    <td>$699</td>  </tr></table>
          <table>
  <tr>
    <th>Модель</th>
    <th>Цена</th>
  </tr>
  <tr>
    <td>iPhone 12 Pro</td>
    <td>$999</td>
  </tr>
  <tr>
    <td>iPhone 12</td>
    <td>$799</td>
  </tr>
  <tr>
    <td>iPhone 12 mini</td>
    <td>$699</td>
  </tr>
</table>

        
        
          
        
      

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

Открыть демо в новой вкладке

«th» расшифровывается как «table header» и переводится «заголовок таблицы».

Теги логической группировки

Секция статьи "Теги логической группировки"

Существуют также теги <thead>, <tbody>, <tfoot> и <caption>. Казалось бы, у нас уже есть прекрасно выглядящая таблица. К чему усложнять?

Во-первых, это красиво 😄

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

К тому же, правильно свёрстанная таблица может отобразиться в поисковике в виде сниппета.

Сниппет с таблицей расписания поездов на странице поисковой выдачи Google

<thead>

Секция статьи ""

Тег <thead> отвечает за шапку таблицы. Внутри этого тега могут располагаться одна или более строк с заголовками таблицы. <thead> должен располагаться в разметке сразу за открывающим <table> или после <caption>, но строго до <tbody> и <tfoot>.

<thead> по своей семантике похож на тег <header>, только его «влияние» распространяется в пределах таблицы.

Наличие этих тегов в разметке удобно и с точки зрения стилизации. Можно разом применить стили к блоку целиком, используя селекторы thead, tbody или table :not(tbody) (почему бы и нет? 😏)

Добавим в нашу таблицу <thead>:

        
          
          <table>  <thead>    <tr>      <th>Модель</th>      <th>Цена</th>    </tr>  </thead>  <tr>    <td>iPhone 12 Pro</td>    <td>$999</td>  </tr>  <tr>    <td>iPhone 12</td>    <td>$799</td>  </tr>  <tr>    <td>iPhone 12 mini</td>    <td>$699</td>  </tr></table>
          <table>
  <thead>
    <tr>
      <th>Модель</th>
      <th>Цена</th>
    </tr>
  </thead>
  <tr>
    <td>iPhone 12 Pro</td>
    <td>$999</td>
  </tr>
  <tr>
    <td>iPhone 12</td>
    <td>$799</td>
  </tr>
  <tr>
    <td>iPhone 12 mini</td>
    <td>$699</td>
  </tr>
</table>

        
        
          
        
      

<tbody>

Секция статьи ""

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

Этот тег схож по семантике с <main>, но в пределах таблицы.

Обернём все айфоны в один <tbody> и добавим пару андроидов, чтобы показать, что может быть больше одного блока данных:

        
          
          <table>  <thead>    <tr>      <th>Модель</th>      <th>Цена</th>    </tr>  </thead>  <tbody>    <tr>      <td>iPhone 12 Pro</td>      <td>$999</td>    </tr>    <tr>      <td>iPhone 12</td>      <td>$799</td>    </tr>    <tr>      <td>iPhone 12 mini</td>      <td>$699</td>    </tr>  </tbody>  <tbody>    <tr>      <td>Xiaomi Mi 10</td>      <td>$768</td>    </tr>    <tr>      <td>Xiaomi Black Shark 3 128 Gb</td>      <td>$529</td>    </tr>  </tbody></table>
          <table>
  <thead>
    <tr>
      <th>Модель</th>
      <th>Цена</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>iPhone 12 Pro</td>
      <td>$999</td>
    </tr>
    <tr>
      <td>iPhone 12</td>
      <td>$799</td>
    </tr>
    <tr>
      <td>iPhone 12 mini</td>
      <td>$699</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td>Xiaomi Mi 10</td>
      <td>$768</td>
    </tr>
    <tr>
      <td>Xiaomi Black Shark 3 128 Gb</td>
      <td>$529</td>
    </tr>
  </tbody>
</table>

        
        
          
        
      

<tfoot>

Секция статьи ""

Тег <tfoot> нужен для строки «Итого» — некой строки с итогом данных таблицы. В таблице может быть только один блок <tfoot>.

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

Если по какой-то причине вы не использовали в таблице <thead> или <tbody>, то футер будет отрисован после всех <tr>.

По семантике этот тег похож на <footer>, только в пределах таблицы.

Добавим в нашу таблицу строку со средней ценой всех телефонов:

        
          
          <table>  <thead>    <tr>      <th>Модель</th>      <th>Цена</th>    </tr>  </thead>  <tbody>    <tr>      <td>iPhone 12 Pro</td>      <td>$999</td>    </tr>    <tr>      <td>iPhone 12</td>      <td>$799</td>    </tr>    <tr>      <td>iPhone 12 mini</td>      <td>$699</td>    </tr>  </tbody>  <tbody>    <tr>      <td>Xiaomi Mi 10</td>      <td>$768</td>    </tr>    <tr>      <td>Xiaomi Black Shark 3 128 Gb</td>      <td>$529</td>    </tr>  </tbody>  <tfoot>    <tr>      <td>Средняя цена:</td>      <td>$758.8</td>    </tr>  </tfoot></table>
          <table>
  <thead>
    <tr>
      <th>Модель</th>
      <th>Цена</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>iPhone 12 Pro</td>
      <td>$999</td>
    </tr>
    <tr>
      <td>iPhone 12</td>
      <td>$799</td>
    </tr>
    <tr>
      <td>iPhone 12 mini</td>
      <td>$699</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td>Xiaomi Mi 10</td>
      <td>$768</td>
    </tr>
    <tr>
      <td>Xiaomi Black Shark 3 128 Gb</td>
      <td>$529</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td>Средняя цена:</td>
      <td>$758.8</td>
    </tr>
  </tfoot>
</table>

        
        
          
        
      
Открыть демо в новой вкладке

<caption>

Секция статьи ""

Если нужно подписать таблицу, дать ей определение, то можно использовать парный тег <caption>. В него помещается общая информация о таблице. Подробнее в статье про <caption>.

Например, для нашей таблицы прекрасно подошло бы описание «Цены на флагманские модели iPhone и Xiaomi». Добавим его в разметку (часть данных опущена для краткости):

        
          
          <table>  <caption>Цены на флагманские модели iPhone и Xiaomi</caption>  <thead>    <tr>      <th>Модель</th>      <th>Цена</th>    </tr>  </thead>  <tbody>    <!--  Данные по iPhone  -->  </tbody>  <tbody>    <!-- Данные по Xiaomi -->  </tbody>  <tfoot>    <tr>      <td>Средняя цена:</td>      <td>$758.8</td>    </tr>  </tfoot></table>
          <table>
  <caption>Цены на флагманские модели iPhone и Xiaomi</caption>
  <thead>
    <tr>
      <th>Модель</th>
      <th>Цена</th>
    </tr>
  </thead>
  <tbody>
    <!--  Данные по iPhone  -->
  </tbody>
  <tbody>
    <!-- Данные по Xiaomi -->
  </tbody>
  <tfoot>
    <tr>
      <td>Средняя цена:</td>
      <td>$758.8</td>
    </tr>
  </tfoot>
</table>

        
        
          
        
      
Открыть демо в новой вкладке

Атрибуты

Секция статьи "Атрибуты"

Помимо глобальных атрибутов при работе с таблицами вам могут очень пригодиться атрибуты colspan и rowspan. Оба атрибута предназначены для объединения ячеек. colspan нужен для объединения ячеек из 2 или более столбцов, а rowspan для объединения ячеек из 2 или более рядов.

Разделим описание телефонов на производителя и модель. Производитель будет повторяться, объединим ячейки с его названием во всех рядах. Добавим один заголовок «Производитель», а в первые <tr> каждого из <tbody> — название модели, и применим атрибут rowspan. Теперь эти ячейки занимают собой пространство в 3 и 2 ряда соответственно.

        
          
          <table>  <caption>Цены на флагманские модели iPhone и Xiaomi</caption>  <thead>    <tr>      <th>Производитель</th>      <th>Модель</th>      <th>Цена</th>    </tr>  </thead>  <tbody>    <tr>      <td rowspan="3">iPhone</td>      <td>12 Pro</td>      <td>$999</td>    </tr>    <tr>      <td>12</td>      <td>$799</td>    </tr>    <tr>      <td>12 mini</td>      <td>$699</td>    </tr>  </tbody>  <tbody>    <tr>      <td rowspan="2">Xiaomi</td>      <td>Mi 10</td>      <td>$768</td>    </tr>    <tr>      <td>Black Shark 3 128 Gb</td>      <td>$529</td>    </tr>  </tbody>  <tfoot>    <tr>      <td>Средняя цена:</td>      <td>$758.8</td>    </tr>  </tfoot></table>
          <table>
  <caption>Цены на флагманские модели iPhone и Xiaomi</caption>
  <thead>
    <tr>
      <th>Производитель</th>
      <th>Модель</th>
      <th>Цена</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan="3">iPhone</td>
      <td>12 Pro</td>
      <td>$999</td>
    </tr>
    <tr>
      <td>12</td>
      <td>$799</td>
    </tr>
    <tr>
      <td>12 mini</td>
      <td>$699</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td rowspan="2">Xiaomi</td>
      <td>Mi 10</td>
      <td>$768</td>
    </tr>
    <tr>
      <td>Black Shark 3 128 Gb</td>
      <td>$529</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td>Средняя цена:</td>
      <td>$758.8</td>
    </tr>
  </tfoot>
</table>

        
        
          
        
      
Открыть демо в новой вкладке

Но теперь в итоговой строке количество ячеек не совпадает с общим числом колонок в таблице. Растянем первую ячейку на две колонки:

        
          
          <table>  <caption>Цены на флагманские модели iPhone и Xiaomi</caption>  <thead>    <tr>      <th>Производитель</th>      <th>Модель</th>      <th>Цена</th>    </tr>  </thead>  <tbody>    <tr>      <td rowspan="3">iPhone</td>      <td>12 Pro</td>      <td>$999</td>    </tr>    <tr>      <td>12</td>      <td>$799</td>    </tr>    <tr>      <td>12 mini</td>      <td>$699</td>    </tr>  </tbody>  <tbody>    <tr>      <td rowspan="2">Xiaomi</td>      <td>Mi 10</td>      <td>$768</td>    </tr>    <tr>      <td>Black Shark 3 128 Gb</td>      <td>$529</td>    </tr>  </tbody>  <tfoot>    <tr>      <td colspan="2">Средняя цена:</td>      <td>$758.8</td>    </tr>  </tfoot></table>
          <table>
  <caption>Цены на флагманские модели iPhone и Xiaomi</caption>
  <thead>
    <tr>
      <th>Производитель</th>
      <th>Модель</th>
      <th>Цена</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan="3">iPhone</td>
      <td>12 Pro</td>
      <td>$999</td>
    </tr>
    <tr>
      <td>12</td>
      <td>$799</td>
    </tr>
    <tr>
      <td>12 mini</td>
      <td>$699</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <td rowspan="2">Xiaomi</td>
      <td>Mi 10</td>
      <td>$768</td>
    </tr>
    <tr>
      <td>Black Shark 3 128 Gb</td>
      <td>$529</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td colspan="2">Средняя цена:</td>
      <td>$758.8</td>
    </tr>
  </tfoot>
</table>

        
        
          
        
      
Открыть демо в новой вкладке

Подсказки

Секция статьи "Подсказки"

💡 У таблицы нет встроенных стилей для отображения границ ячеек. Не удивляйтесь, если, написав разметку, вы не увидите рамки. Используйте CSS-свойство border.

Задать границы элементам <tr>, <thead>, <tfoot> и <tbody> нельзя, поэтому задавайте их тегам <table>, <th> или <td>.

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

💡 Средствами CSS можно создать конструкцию, визуально максимально похожую на таблицу, но лучше так не делать. Важно не только внешнее сходство, но и смысловая нагрузка. Проще всего добиться совпадения смысла и визуального сходства, используя теги из этой статьи.

💡 Ширина таблицы по умолчанию подстраивается под контент внутри, если не задавать дополнительные CSS-свойства.

Это приводит к определённым сложностям на адаптивных сайтах. Если контент не помещается на маленький экран, то таблица не сжимается, у неё появляется горизонтальный скролл.

У этой проблемы есть несколько потенциальных решений: скрывать не первостепенную информацию для пользователей мобильных устройств или перестраивать отображение таблицы, например, при помощи свойства display.

На практике

Секция статьи "На практике"

Алёна Батицкая советует

Секция статьи "Алёна Батицкая советует"

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

Например, сделаем каждую вторую строку с коричневым фоном. Для этого понадобится всего одно CSS-правило с псевдоклассом :nth-child():

        
          
          tr:nth-child(odd) {  background-color: #663613;}
          tr:nth-child(odd) {
  background-color: #663613;
}

        
        
          
        
      

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

        
          
          tbody tr:nth-child(odd) {  background-color: #663613;}
          tbody tr:nth-child(odd) {
  background-color: #663613;
}

        
        
          
        
      
Открыть демо в новой вкладке

🛠 Можно сделать так, чтобы строка с заголовками колонок прилипала при прокрутке длинной таблицы. Это удобно, если данных много и пользователь может просто забыть, в какой колонке какие данные.

Это довольно просто сделать при помощи position: sticky. Имейте в виду, что нельзя применить это свойство к тегам <thead> или <tr>, поэтому применим его к <th>.

        
          
          th {  position: -webkit-sticky;  position: sticky;  top: 0;  z-index: 1;}
          th {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 1;
}

        
        
          
        
      

Не забудьте добавить position: relative для родителя. Заодно подстрахуемся и сделаем прилипающими только заголовки в шапке таблицы.

        
          
          table {  position: relative;}thead th {  position: sticky;  position: -webkit-sticky;  top: 0;  z-index: 1;}
          table {
  position: relative;
}

thead th {
  position: sticky;
  position: -webkit-sticky;
  top: 0;
  z-index: 1;
}

        
        
          
        
      

Задайте фон заголовкам, чтобы текст ячеек не был виден при прокрутке. А чтобы избавиться от линий между ячейками, зададим для всей таблицы свойство border-collapse: collapse:

        
          
          table {  position: relative;  border-collapse: collapse;}thead th {  position: -webkit-sticky;  position: sticky;  top: 0;  z-index: 1;  background-color: #FF8630;}
          table {
  position: relative;
  border-collapse: collapse;
}

thead th {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 1;
  background-color: #FF8630;
}

        
        
          
        
      
Открыть демо в новой вкладке