Руководство по стилизации таблиц
Недавно я заметил небольшой парадокс: много лет назад — до появления 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 с кучей демо: