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

Таблицы

Как устроены таблицы в 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;
}

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