Тег tr в HTML: строка таблицы, атрибуты, стили и JavaScript

Тег tr (от английского table row, «строка таблицы») задаёт одну горизонтальную строку: внутри записывают ячейки td с данными и th с заголовками. Число колонок таблицы определяют ячейки всех строк вместе, а сам тег tr почти ничего не рисует и не имеет собственных атрибутов.

Как строки и ячейки складываются в таблицу, объясняет урок «Строки tr и ячейки td». Здесь разберём остальное: какие атрибуты у строки устарели, а каких у неё нет совсем, какие стили на неё действуют, как выделять строки и собирать их в карточки, как не разорвать строку при печати и как работать с ней из скрипта.

HTML
<table>
  <tr>
    <th scope="col">Чай</th>
    <th scope="col">Цена</th>
  </tr>
  <tr>
    <td>Сенча</td>
    <td>100</td>
  </tr>
</table>

Тег tr в HTML: что это и что записывают внутри

Внутри tr записывают только ячейки: td для данных и th для заголовков, в любом сочетании. Для скринридера строка получает роль row, а ячейки th со scope становятся заголовками колонки или строки. Свои атрибуты у тега не определены, допустимы только глобальные: id, class, hidden, tabindex, data-*. Закрывающий тег можно опустить, если следом идёт другая строка или кончается секция.

Сетку таблицы задаёт самая широкая строка: короткие строки остаются с пустым местом справа, а строка длиннее первой добавляет таблице лишнюю колонку. Одну ячейку на всю ширину делает colspan. Валидатор Nu считает строку без ячеек ошибкой, а про строки разной длины только предупреждает.

ЗаписьЧто получаетсяПример записи
td в trЯчейка с данными<td>100</td>
th в trЗаголовок столбца или строки<th scope="col">Цена</th>
Строка короче остальныхСправа пустое место, валидатор предупреждает<tr><td>Улун</td></tr>
Строка длиннее первойТаблица получает лишнюю колонку, валидатор предупреждает<tr><td>Сенча</td><td>100</td><td>новинка</td></tr>
Строка с colspanОдна ячейка на всю ширину, замечаний нет<tr><td colspan="2">Скидка</td></tr>
tr без ячеекПустая строка, валидатор считает её ошибкой<tr></tr>

Пример: ячейки в строке

Результат

Выберите запись: вверху виден код, под ним — что получилось на экране.

Где записывать tr: родители, опущенные теги и строки вне таблицы

Родителем tr служит одна из секций: thead, tbody или tfoot. Стандарт разрешает записывать строки и прямо в table, но браузер всё равно создаёт tbody сам, поэтому селектор table > tr ничего не находит, а table > tbody > tr находит. Как браузер строит секции при опущенных тегах, описано на странице tbody.

Закрывающие </tr> и </td> можно опустить: границы определяются по следующему тегу. Вне таблицы tr теряется: браузер отбрасывает теги и оставляет только текст. Текст и div прямо в строке выносятся перед таблицу. Вложенный tr не создаёт таблицу в таблице, а становится следующей строкой: для вложенной таблицы в ячейку записывают полный тег table.

Как записаноЧто делает браузерПример записи
tr в tbodyОставляет как есть<tbody><tr>...</tr></tbody>
tr прямо в tableСоздаёт tbody сам<table><tr>...</tr></table>
Опущены </tr> и </td>Разделяет строки и ячейки по следующему тегу<tr><td>Сенча<td>100<tr><td>Улун
tr внутри trДелает вложенную строку соседней<tr><td>Сенча<tr><td>Улун
Текст или div в trВыносит их перед таблицу<tr>Итого<td>Сенча</td></tr>
tr вне tableОтбрасывает теги, остаётся текст<div><tr><td>Сенча</td></tr></div>

Пример: как браузер разбирает строки

Результат

Выберите запись: вверху виден код, под ним — что построил браузер.

Допустимые места записи перечислены в описании элемента в стандарте HTML.

Атрибуты tr: что устарело и чего не существует

Собственных атрибутов у tr в стандарте нет. Старые align, valign, bgcolor и height считаются устаревшими: Chrome их выполняет, а валидатор Nu выдаёт предупреждение. Атрибутов width и colspan у tr не существует совсем: валидатор считает их ошибкой, а браузер их игнорирует. Ширину задают ячейкам, а колонки объединяет colspan у td и th.

Из глобальных атрибутов строке полезны hidden (скрывает строку), tabindex (делает строку доступной с клавиатуры), aria-selected (отмечает выбранную строку) и data-* (хранит данные для скрипта). Атрибут role="row" писать не нужно: роль у строки есть, а валидатор считает такую запись ошибкой.

АтрибутЧто получаетсяПример записи
bgcolorУстарел: строка закрашивается, валидатор предупреждаетСвойство background
alignУстарел: текст выравнивается, валидатор предупреждаетСвойство text-align
valignУстарел: ячейки выравниваются по вертикали, валидатор предупреждаетСвойство vertical-align
heightУстарел: задаёт минимальную высоту строки, валидатор предупреждаетСвойство height
widthНе существует: валидатор считает ошибкой, браузер игнорируетШирина у ячеек: td { width: 110px; }
colspanНе существует: валидатор считает ошибкой, браузер игнорирует<td colspan="2">Скидка</td>
hiddenДопустим: скрывает строку<tr hidden>
tabindex, aria-selected, data-*Допустимы<tr tabindex="0" aria-selected="true" data-id="5">
role="row"Валидатор считает ошибкой: роль у строки уже естьУбрать атрибут

Пример: атрибуты строки и их замена

Результат

Выберите атрибут: вверху виден код, под ним — что сделал браузер и что сказал бы валидатор.

CSS
tr {
  background: #ffd9a8;
  text-align: right;
  vertical-align: bottom;
  height: 100px;
}
td, th {
  width: 110px;
}

Стили tr: фон, рамка, высота и наследование

Строка в CSS ведёт себя не как блок: у неё есть фон, высота и наследуемые свойства, но рамка, скругление, отступы и ширина либо зависят от режима таблицы, либо не действуют вовсе. Цвет, размер шрифта, text-align и vertical-align у tr наследуют и td, и th, так же как у секций, о чём подробнее на странице thead. Жирность у th задана браузером, и от строки она не меняется.

Свойство у trЧто получаетсяПример записи
backgroundЗакрашивает ячейки строки, промежутки border-spacing остаются без фона; фон td перекрывает фон строкиtr { background: #ffd9a8; }
borderРисуется только при border-collapse: collapsetr { border-bottom: 1px solid #b8b0a0; }
border-radiusНе действует: скругляют первую и последнюю ячейкиtd:first-child { border-radius: 8px 0 0 8px; }
padding, marginНе действуют: отступы задают ячейкамtd { padding: 8px; }
widthНе действует: ширину задают ячейкамtd { width: 110px; }
heightЗадаёт минимум: ячейка с большим содержимым растянет строкуtr { height: 80px; }
outline, box-shadowРаботают, размеры не меняютсяtr { box-shadow: inset 0 0 0 3px #c0292e; }
transformРаботает: строка сдвигается целикомtr:hover { transform: translateX(8px); }
color, text-align, font-weightПервые два наследуют td и th, жирность меняется только у td: у th она задана браузеромtr { text-align: right; }

Пример: что действует на строку

Результат

Выберите свойство и при желании включите border-collapse: collapse: результат виден сразу.

CSS
table {
  border-collapse: collapse;
}
tr {
  height: 40px;
  vertical-align: middle;
  border-bottom: 1px solid #b8b0a0;
}
td:first-child {
  border-radius: 8px 0 0 8px;
}
td:last-child {
  border-radius: 0 8px 8px 0;
}

Зебра, наведение и выбор строки tr в CSS

Чередование цветов, подсветка под курсором и выбор строки записывают селекторами на tr. Нумерация :nth-child() начинается заново в каждой секции: шапка не сдвигает полосы тела, а в таблице из нескольких tbody полосы в каждой группе начинаются с начала. Чем отличается счёт у самих секций tbody, описано на странице tbody.

ЗаписьЧто получаетсяПример записи
tbody tr:nth-child(even)Чётные строки каждого tbodytbody tr:nth-child(even) { ... }
tr:hoverСтрока под курсором; работает, если у ячеек нет своего фонаtr:hover { background: #ffd9a8; }
tr:hover tdПодсветка видна и при фоне у ячеекtr:hover td { background: #ffd9a8; }
tr:has(input:checked)Строка с отмеченным флажкомtr:has(input:checked) { ... }
tr:focus-withinСтрока, в которой находится фокусtr:focus-within { outline: 3px solid; }
tr:last-childПоследняя строка каждой секцииtr:last-child { border-bottom: 0; }
tr[aria-selected="true"]Выбранная строка: атрибут переключает скриптtr[aria-selected="true"] { ... }

Пример: полосы, наведение и выбор строки

Результат

Выберите правило: вверху виден код, под ним таблица, на которой правило можно проверить мышью и клавиатурой.

Строке, которую выбирают с клавиатуры, задают tabindex="0": тогда она получает фокус клавишей Tab, а скрипт может переключать aria-selected по Enter.

CSS
tbody tr:nth-child(even) {
  background: #f5f1ea;
}
tr:hover td {
  background: #ffe9c7;
}
tr[aria-selected="true"] td {
  background: #ffd9a8;
}

Строки tr карточками на узком экране

На узком экране широкую таблицу перестраивают: строкам и ячейкам задают display: block, и каждая строка становится карточкой. Названия колонок берут из атрибута data-label у ячейки и выводят псевдоэлементом ::before, а шапку прячут не через display: none, а так, чтобы она осталась для скринридера.

У такой раскладки есть ловушка: как только строке задан display, атрибут hidden перестаёт её скрывать, потому что правило автора перекрывает стиль браузера. Скрытая строка появляется снова, пока не добавить tr[hidden] { display: none; }.

ЗаписьРезультатПример записи
tr, td с display: blockЯчейки встают столбиком, строки отделяются друг от другаtr, td { display: block; }
td::before с data-labelНазвание колонки выводится перед значениемtd::before { content: attr(data-label); }
Шапка с display: noneНазвания колонок пропадают и для скринридераthead { display: none; }
Шапка с обрезкой по размеруШапка невидима, но остаётся в дереве доступности (проверено в Chrome)thead { position: absolute; clip: rect(0 0 0 0); }
tr с display: flexЯчейки выстраиваются в ряд по ширине содержимогоtr { display: flex; }
display: flex и hiddenСкрытая строка снова видна<tr hidden>
tr[hidden] с display: nonehidden снова скрывает строкуtr[hidden] { display: none; }

Пример: таблица и карточки

Результат

Выберите вариант: вверху виден код, под ним таблица. Одна строка в таблице скрыта атрибутом hidden.

CSS
@media (max-width: 600px) {
  thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
  tr, td {
    display: block;
  }
  td::before {
    content: attr(data-label);
    font-weight: 600;
  }
  tr[hidden] {
    display: none;
  }
}
HTML
<tr>
  <td data-label="Чай">Сенча</td>
  <td data-label="Цена">100</td>
  <td data-label="Вес">50 г</td>
</tr>

Печать tr: как не разорвать строку между страницами

При печати строка таблицы может разорваться: верх ячеек остаётся на одной странице, а низ переходит на следующую. В пробной таблице из 30 строк по шесть строк текста в ячейке на листах A4 разорвались две строки из тридцати. Правило break-inside: avoid у tr оставляет строку целой: если она не помещается, браузер переносит её на следующую страницу. То же правило для целой группы строк описано на странице tbody, а повтор шапки и подвала на каждой странице — на странице thead.

CSS
@media print {
  tr {
    break-inside: avoid;
  }
}
ЗаписьРезультат при печатиПример записи
Без правилСтрока на границе страниц может разорваться<tr>...</tr>
tr с break-inside: avoidСтрока переносится на следующую страницу целикомtr { break-inside: avoid; }

Результат видно в предпросмотре печати: Ctrl + P.

Тег tr и JavaScript: rowIndex, cells и insertCell

Строка в скрипте представлена интерфейсом HTMLTableRowElement. Свойство rowIndex возвращает номер строки в таблице в порядке «шапка, тело, подвал», sectionRowIndex — номер внутри секции, cells — все ячейки строки, и td, и th. Метод insertCell() добавляет ячейку, deleteCell() удаляет. У строки вне таблицы rowIndex равен -1.

ЗаписьЧто делаетПример записи
row.rowIndexВозвращает номер строки в таблицеrow.rowIndex
row.sectionRowIndexВозвращает номер строки внутри секцииrow.sectionRowIndex
row.cellsВозвращает ячейки td и th строкиrow.cells[0]
row.insertCell(-1)Добавляет в конец строки ячейку tdrow.insertCell(-1)
row.deleteCell(-1)Удаляет последнюю ячейкуrow.deleteCell(-1)
row.cloneNode(true)Копирует строку вместе с ячейкамиrow.cloneNode(true)
e.target.closest("tr")Находит строку, в которой произошёл кликe.target.closest("tr")

Пример: методы строки

Результат

Выберите действие: вверху виден код, под ним таблица и результат, который считает сама страница.

JavaScript
table.addEventListener('click', (event) => {
  const row = event.target.closest('tr');
  if (!row || !table.contains(row)) return;
  for (const other of table.rows) {
    other.removeAttribute('aria-selected');
  }
  row.setAttribute('aria-selected', 'true');
});

Метод insertCell() всегда создаёт td, поэтому ячейку-заголовок создают через document.createElement('th'). Метод table.deleteRow(-1) удаляет последнюю строку всей таблицы, а при наличии подвала это строка подвала: строки тела удаляют методом tbody.deleteRow(-1). Добавление строк в тело разобрано на странице tbody, а создание подвала — на странице tfoot.

Частые ошибки с тегом tr

Типичные ошибки со строками таблицы и как их исправить.

ОшибкаЧто происходитКак исправить
width или colspan у trБраузер игнорирует, валидатор считает ошибкойШирину задавать ячейкам, колонки объединять через colspan у td
Пустой tr для промежутка между строкамиВалидатор считает строку без ячеек ошибкойtable { border-spacing: 0 8px; }
Разное число ячеек в строкахСправа остаётся пустое место, валидатор предупреждаетДописать ячейки или использовать colspan
border у tr без collapseРамка не рисуетсяВключить border-collapse: collapse или задать границы ячейкам
border-radius, padding, margin у trСвойства не действуютЗадавать их ячейкам
Атрибуты bgcolor, align, valign, heightУстарели, валидатор предупреждаетСвойства background, text-align, vertical-align, height
Текст или div прямо в trБраузер выносит их перед таблицуЗаписывать в ячейку td
tr вне tableТеги пропадают, остаётся текстЗаписывать строки внутри table
table > tr в CSS или скриптеНичего не находит: браузер добавил tbodytable > tbody > tr
tr:hover при фоне у ячеекПодсветки не видноtr:hover td { background: #ffe9c7; }
display: flex у tr без правила для hiddenСкрытая строка снова виднаtr[hidden] { display: none; }
Строка разрывается при печатиВерх строки на одной странице, низ на другойtr { break-inside: avoid; }
insertCell() в строке шапкиСоздаётся td, а не thdocument.createElement('th')
table.deleteRow(-1) при подвалеУдаляется строка подвалаtbody.deleteRow(-1)
role="row" у trВалидатор считает ошибкой: роль уже естьУбрать атрибут
Категория
Поделиться в социальных сетях

Отправить комментарий

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×