Оформляем таблицы с помощью CSS: как работать с полями, границами и свойством z-index

Читать в полной версии →

Ещё несколько лет назад фронтенд-разработчики активно использовали табличную вёрстку для создания веб-страниц. Сегодня появились более удобные инструменты, а тег <table> теперь применяется по прямому назначению: для создания таблиц с данными. Однако оформлять таблицы по-прежнему не так просто. Некоторые CSS-свойства, например, margin, border-radius, z-index, не работают с элементами таблиц <tbody>, <thead>, <tr>. Статья поможет обойти эти ограничения.

Структура таблицы

Эталонный вариант таблицы


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

<table class="table">
  <thead>
    <tr>
      <th>MO</th>
      <th>TU</th>
      <th>WE</th>
      <th>TH</th>
      <th>FR</th>
      <th>SA</th>
      <th>SU</th>
    </tr>
  </thead>
  <tbody class="section section-step">
    <tr class="sub-header">
      <th colspan="7">
        Working hours
      </th>
    </tr>
    <tr>
      <td>4</td>
      <td>5</td>
      <td>5</td>
      <td>5</td>
      <td>5</td>
      <td>0</td>
      <td>0</td>
    </tr>
  </tbody>
  <tbody class="section section-step">
    <tr class="sub-header">
      <th colspan="7">
        Workout
      </th>
    </tr>
    <tr>
      <td>0.5</td>
      <td>0.5</td>
      <td>0.5</td>
      <td>1</td>
      <td>0.5</td>
      <td>2</td>
      <td>0</td>
    </tr>
  </tbody>
  <tbody class="section">
    <tr class="section-header">
      <th colspan="7">
        Total
      </th>
    </tr>
    <tr>
      <td>8.5</td>
      <td>8.5</td>
      <td>9.5</td>
      <td>10</td>
      <td>5.5</td>
      <td>2</td>
      <td>0</td>
    </tr>
  </tbody>
</table>

Выше представлена структура таблицы в HTML. В <thead> содержится главное название. В таблице есть несколько секций <tbody>, каждая из которых имеет собственный подзаголовок.

Что не так с margin и как оформить отступы для элементов таблицы

Как видно на иллюстрации в начале статьи, между главным заголовком и секцией <tbody>, а также между остальными секциями <tbody>, есть отступы. Можно подумать, что они определяются свойствами margin-top для <tbody>, но это не так.

Если попытаться использовать margin-top для оформления <tbody>, <thead> или <tr>, добиться отступов не удастся. Чтобы margin заработали, можно изменить свойство display, которое менять опасно, так как изменения могут нарушить форматирование таблицы. Поэтому лучше воспользоваться альтернативными решениями, которые описаны ниже.

Свойство border

Самый простой способ получить отступы без использования margin — применить к <tbody> border-top: 1 em.

// Это нужно, чтобы работал border-top
.table {
  border-collapse: collapse; // 1
  border-spacing: 0;
}

.section {
  border-top: 1em solid transparent;
}

Все секции <tbody>, у которых должны быть отступы, имеют класс .section. Чтобы свойство border-top сработало, необходимо применить к таблице border-collapse: collapse.

Псевдоэлементы ::before и ::after

Псевдоэлементы ::before и ::after — ещё один способ добавить отступы для элементов таблицы.

.section::before {
  height: 1em;
  display: table-row;
  content: '';
}

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

Вы можете использовать для оформления отступов как псевдоэлементы, так и свойство border.

Как применить к элементам таблицы border-radius

Задача: добавить к секциям <tbody> границы и применить к ним border-radius. Напрямую это сделать невозможно — border и border-radius не работают с <tbody>.

// 1. Приходится использовать свойство box-shadow
//    border-radius не работает с <tbody>.
.section-step {
  border-radius: 0.25em; // 1
  box-shadow: 0 0 0 1px #ccc; // 1
}

Пример выше показывает, как с помощью box-shadow добиться практически такого же результата, как с помощью border при работе с нетабличными элементами.

Как оформлять ячейки таблицы

Внешний вид текущей таблицы (см. иллюстрацию ниже) отличается от эталонного варианта, который представлен в начале статьи.

Нужны марджины, а не паддинги


После добавления границ можно заметить, что полученные отступы работают не как «марджины», а как «паддинги». Это можно изменить, если работать с границами ячеек и использовать селекторы :first-child и :last-child.

.section-step th,
.section-step td {
  border: 0 solid #ccc;
}

.section-step th:first-child,
.section-step td:first-child {
  border-left-width: 1px;
}

.section-step th:last-child,
.section-step td:last-child {
  border-right-width: 1px;
}

.section-step tr:first-child th,
.section-step tr:first-child td {
  border-top-width: 1px;
}

.section-step tr:first-child th:first-child,
.section-step tr:first-child td:first-child {
  border-top-left-radius: 0.25em;
}

.section-step tr:first-child th:last-child,
.section-step tr:first-child td:last-child {
  border-top-right-radius: 0.25em;
}

.section-step tr:last-child th,
.section-step tr:last-child td {
  border-bottom-width: 1px;
}

.section-step tr:last-child th:first-child,
.section-step tr:last-child td:first-child {
  border-bottom-left-radius: 0.25em;
}

.section-step tr:last-child th:last-child,
.section-step tr:last-child td:last-child {
  border-bottom-right-radius: 0.25em;
}

В примере выше стили применяются к соответствующим элементам th и td ячеек таблицы. К ячейкам, которые находятся в углах таблицы, применяется border-radius. Все ячейки, которые находятся по краям таблицы, имеют границы. Селекторы :first-child и :last-child позволяют обращаться к нужным ячейкам.

Как применять z-index к элементам таблицы

Проблемы с box-shadow


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

В обычной ситуации можно использовать для решения таких проблем z-index. Но с таблицами всё сложнее: z-index не работает с <tbody>. Проблема решается, если вы знаете, как работать с контекстом наложения. Если применить к элементу position: relative и z-index, появляется новый контекст наложения. Также эту задачу можно решить с помощью transform: translate (0, 0).

Заключение

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

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

Адаптированный перевод статьи Styling HTML Tables: How to Apply Margins, Borders and z-index on Table Elements by Markus Oberlehner. Мнение автора оригинальной публикации может не совпадать с мнением администрации «Хекслета».