Руководство по стилизации таблиц
Недавно я заметил небольшой парадокс: много лет назад — до появления CSS Grid — мы использовали <table>
для имитации макетов сетки. Теперь, когда у нас есть макеты сетки, мы используем их для моделирования таблиц! Это неправильно. Таблицы предназначены для табличных данных; и нет смысла представлять табличные данные в группе <div>
.
Причина этой злоупотребления может заключаться в том, что таблицы могут быть немного сложными для стилизации, и что большинство фреймворков CSS используют border-collapse
: коллапс для стилизации таблиц по умолчанию. Как мы увидим в этом уроке, свернутые границы не всегда полезны для стилизации таблицы.
Давайте рассмотрим элементы <table>
, а затем их структурирование и стилизацию.
Элементы
Помимо самого элемента <table>
, для создания базовой таблицы вам понадобятся только эти 3 тега:
Пример:
<table>
<tr><th>Header</th></tr>
<tr><td>Content</td></tr>
</table>
Однако, чтобы лучше структурировать таблицу, мы можем инкапсулировать строки в:
Наконец, мы можем добавить <caption>
в таблицу и определить столбцы в тегах <col>
внутри <colgroup>
.
Пример:
<table>
<caption>Super Heroes</caption>
<colgroup><col><col><col><col></colgroup>
<thead>
<tr><th>First Name</th><th>Last Name</th><th>Known As</th><th>Place</th></tr>
</thead>
<tbody>
<tr><td>Bruce</td><td>Wayne</td><td>Batman</td><td>Gotham City</td></tr>
<tr><td>Clark</td><td>Kent</td><td>Superman</td><td>Metropolis</td></tr>
<tr><td>Tony</td><td>Stark</td><td>Iron Man</td><td>Malibu</td></tr>
<tr><td>Peter</td><td>Parker</td><td>Spider-Man</td><td>New York City</td></tr>
<tr><td>Matt</td><td>Murdock</td><td>Daredevil</td><td>New York City</td></tr>
</tbody>
</table>
Без каких-либо стилей ваш браузер отобразит это:
Стили пользовательского агента по умолчанию:
table {
border-collapse: separate;
text-indent: initial;
border-spacing: 2px;
}
Теперь, если мы добавим очень простое правило:
:is(td,th) {
border-style: solid;
}
Обратите внимание на отдельные границы. Это выглядит не слишком красиво...
Итак, чтобы понять популярность свернутых границ (а также лучшего шрифта!), если мы просто добавим:
table {
border-collapse: collapse;
font-family: system-ui;
}
Мы получаем:
Если мы затем добавим дополнение: .5ch 1ch
к нашему :is(td,th)
-селектору и поля-блоку: 1rlh
к <caption>
, мы получим:
Подводя итог, все, что нам нужно для получения вышеуказанного стиля, это:
table {
border-collapse: collapse;
font-family: system-ui;
& caption { margin-block: 1rlh; }
&:is(td, th) {
border-style: solid;
padding: .5ch 1ch;
}
}
Вместо этого, чтобы разместить <caption>
под таблицей, используйте:
table {
caption-side: bottom;
}
Полосы Зебры
Чтобы добавить нечетные/четные полосы зебры для столбцов, мы можем просто стилизовать тег <col>
:
col:nth-of-type(even) { background: #F2F2F2; }
Для строк это аналогично:
tr:nth-of-type(odd) { background: #F2F2F2; }
Закругленные углы
Закругленные углы немного сложнее. Вы не можете просто добавить border-radius
в <table>
, поэтому нам нужно указать первую и последнюю ячейку первой и последней строк:
th {
&:first-of-type { border-start-start-radius: .5em }
&:last-of-type { border-start-end-radius: .5em }
}
tr {
&:last-of-type {
& td {
&:first-of-type { border-end-start-radius: .5em }
&:last-of-type { border-end-end-radius: .5em }
}
}
}
Но все равно ничего не происходит! Это потому что:
Если у вашей таблицы есть свернутые границы, вы не можете добавить border-radius
.
Поэтому нам придется использовать отдельные границы и просто имитировать свернутые границы:
table {
border-spacing: 0;
}
:is(td, th) {
border-block-width: 1px 0;
border-inline-width: 1px 0;
&:last-of-type { border-inline-end-width: 1px }
}
И теперь у нас есть закругленные углы:
Разделить столбцы
Давайте сохраним отдельные столбцы и воспользуемся свойством border-spacing-spacing
, чтобы добавить пробел между столбцами:
table {
border-spacing: 2ch 0;
& :is(td, th) {
border-inline-width: 1px;
}
}
Мы можем даже добавить border-radius
:
Это по-прежнему просто <table>
, но ее гораздо удобнее читать, если использовать ее в качестве «таблицы сравнения».
Разделить строки
Для разделенных строк нам просто нужно обновить вторую часть (ось Y) свойства border-spacing
:
table {
border-spacing: 0 2ch;
& :is(td, th) {
border-block-width: 1px;
}
}
Наведите курсор и сфокусируйтесь
При работе с большими столами важно точно знать, где вы находитесь. Для этого нам понадобится :hover
и — если вы работаете с таблицей, управляемой с помощью клавиатуры — :focus-visble-styles
.
В этом примере стили наведения применяются как к <col>
, <tr>
, так и к <td>
:
Наводить курсор на строки и ячейки очень просто:
td:hover {
background: #666666;
}
tr:hover {
background: #E6E6E6;
}
Наведение <col>
немного сложнее.
Вы можете добавить правило:
col:hover {
background: #E6E6E6;
}
Но это не работает?
Как ни странно, если вы выберете элемент col
в Dev Tools и включите для него :hover
, он будет работать, но не в реальной жизни.
Вместо этого нам нужно зафиксировать наведение ячеек с помощью :has
, а затем стилизовать элемент <col>
:
table {
&:has(:is(td,th):nth-child(1):hover col:nth-child(1) {
background: #E6E6E6;
}
Итак, что происходит?
Давайте разберемся:
Если в нашей таблице есть <td>
или <th>
, который является nth-child(1)
и он в данный момент наведен, выберите <col>
с тем же nth-child
-селектором и установите его фон.
Уф! ... и вам нужно повторить этот код для каждого столбца: nth-child(2)
, nth-
child(3)
и т.д.
Контуры
Отображать контуры при наведении также просто, то же самое касается ячеек и строк. Вам нужно вычесть ширину из смещения:
:is(td, th, tr):hover {
outline: 2px solid #666;
outline-offset: -2px;
}
Контуры столбцов
Очертить столбец очень сложно, но выглядит красиво:
Если ширина ячейки составляет 1 пиксель, вы можете установить ширину границы <col>
на 2 пикселя при наведении курсора, но тогда вся таблица сместится.
Альваро Монторо предложил использовать фоновые градиенты в <col>
для имитации границы, что отлично работает, если ячейки таблицы прозрачны.
Чтобы заставить его работать с border-radius
и сохранять любой фон, который могли бы иметь ячейки, я в итоге использовал псевдоэлемент для каждой ячейки:
:is(td,th) {
position: relative;
&::after {
border-inline: 2px solid transparent;
border-radius: inherit;
content: '';
inset: -2px 0 0 0;
position: absolute;
}
}
tr:first-of-type th::after {
border-block-start: 2px solid transparent;
}
tr:last-of-type td::after {
border-block-end: 2px solid transparent;
}
А затем, аналогично тому, что мы сделали с col-hover
, нацеливаемся на все ячейки с одинаковым «col-index
» при наведении:
:has(:is(td,th):nth-child(1):hover :is(td,th):nth-child(1) {
border-color: #666;
}
Повторите для всех столбцов
Выравнивание текста
В старой спецификации вы могли добавить свойство align
к элементу <col>
. Это больше не работает.
Пример. Вы хотите центрировать текст во втором столбце и выровнять текст по правому краю в четвертом столбце:
Вместо добавления класса в каждую ячейку мы можем добавить атрибут данных для каждого столбца в саму таблицу:
<table data-c2="center" data-c4="end">
Затем в CSS:
[data-c2~="center"] tr > *:nth-of-type(2) {
text-align: center;
}
[data-c4~="end"] tr > *:nth-of-type(4) {
text-align: end;
}
Повторите для всех столбцов.
Заключение
На этом руководство по стилизации стола заканчивается.
Я не рассмотрел colspan
, rowspan
, область видимости и диапазон. Если вы хотите больше узнать об этом, я предлагаю прочитать страницу MDN посвященную таблицам.
Демо
Я сделал один CodePen с кучей демо: