Таблицы: когда они уместны
Как устроена таблица, зачем нужны thead, caption и scope, как объединять ячейки — и почему вёрстку таблицами делать нельзя.
Что ты научишься делать
- Соберёшь таблицу с заголовками строк и столбцов
- Объединишь ячейки через colspan и rowspan
- Отличишь настоящие табличные данные от вёрстки-в-таблице
#Таблица — для данных, у которых две оси
Таблица нужна, когда у каждого значения есть две координаты: строка и столбец. Расписание: день недели и время. Прайс: товар и характеристика. Сравнение тарифов: тариф и параметр.
Если данные плоские — просто перечисление — это список, а не таблица.
#Из чего собирается таблица
| Тег | Что означает |
|---|---|
table | Сама таблица |
caption | Название таблицы. Идёт первым внутри table |
thead | Шапка: строка с названиями столбцов |
tbody | Тело: основные данные |
tfoot | Итоговая строка: суммы, среднее |
tr | Строка (table row) |
th | Ячейка-заголовок (table header) |
td | Обычная ячейка с данными (table data) |
<table> <caption>Цены на кофе, сентябрь 2026</caption> <thead> <tr> <th scope="col">Напиток</th> <th scope="col">200 мл</th> <th scope="col">300 мл</th> </tr> </thead> <tbody> <tr> <th scope="row">Эспрессо</th> <td>120 ₽</td> <td>—</td> </tr> <tr> <th scope="row">Капучино</th> <td>190 ₽</td> <td>230 ₽</td> </tr> </tbody></table>#scope: главный атрибут доступности
Зрячий человек понимает связи мгновенно: 190 рублей — это капучино на 200 мл, потому что он видит и строку, и столбец. Голосовая программа читает ячейки подряд и без подсказки скажет просто «190 рублей».
scope="col" говорит: «этот заголовок относится ко всему столбцу». scope="row" — «ко всей строке». Тогда читалка произнесёт: «Капучино, 200 мл, 190 рублей».
Так не надо
<tr>
<td>Капучино</td>
<td>190 ₽</td>
</tr>Название напитка — обычная ячейка. Связи между ним и ценой нет, читалка произнесёт два числа подряд.
Так надо
<tr>
<th scope="row">Капучино</th>
<td>190 ₽</td>
</tr>Название стало заголовком строки. Теперь каждая цена в этой строке связана со словом «Капучино».
#Объединение ячеек
colspan растягивает ячейку по горизонтали, rowspan — по вертикали. Число — сколько ячеек занять.
Важно: соседние ячейки, чьё место заняли, из разметки убираются. Иначе строка станет длиннее остальных, и таблица «поедет».
#Итоговая строка: tfoot
У прайса, счёта или отчёта почти всегда есть строка с итогом. Для неё существует отдельный контейнер — tfoot. Он ставится после tbody и говорит браузеру и вспомогательным программам: это не ещё одна строка данных, это сумма.
Отдельный тег окупается сразу: итог можно оформить одним селектором, не выискивая последнюю строку, а при печати длинной таблицы браузер умеет повторять thead и tfoot на каждом листе.
<table> <caption>Заказ на неделю</caption> <thead> <tr><th scope="col">Позиция</th><th scope="col">Сумма</th></tr> </thead> <tbody> <tr><th scope="row">Зёрна, 2 кг</th><td>3400 ₽</td></tr> <tr><th scope="row">Фильтры</th><td>600 ₽</td></tr> </tbody> <tfoot> <tr><th scope="row">Итого</th><td>4000 ₽</td></tr> </tfoot></table>#Как таблицу читает скринридер
Стоит представить, как таблица звучит, — тогда становится понятно, зачем нужны caption и scope. Программа чтения сначала объявляет подпись и размер: «Прайс кофейни, таблица, три столбца, пять строк». Дальше человек ходит по ячейкам стрелками, и на каждой звучит не только её содержимое, но и заголовки, к которым она относится: «Цена, Капучино, 220 рублей».
Именно из scope берётся эта пара «столбец плюс строка». Без него ячейка читается голым числом — «220» — и понять, к чему оно, невозможно, потому что вернуться к шапке глазами нельзя.
Отсюда простое правило проверки: прочитай вслух любую ячейку вместе с её заголовками. Если получилась осмысленная фраза, разметка верная.
#Таблица на маленьком экране
Широкая таблица на телефоне не помещается никак. Самое честное решение — разрешить ей прокручиваться по горизонтали внутри своего контейнера, не растягивая страницу.
Соблазн бывает другой: превратить каждую строку в карточку, а заголовки продублировать через ::before. На двух-трёх столбцах это работает, но с ростом таблицы карточки становятся длиннее экрана, а сравнивать строки между собой — то, ради чего таблицу и делали, — уже невозможно. Прокрутка проще и честнее.
/* Обёртка прокручивается сама, страница остаётся на месте */.table-wrap { overflow-x: auto;}table { min-width: 480px;}Где спотыкаются почти все
Таблицей верстают шапку или галерею
Почему Голосовая программа объявит «таблица, три столбца» там, где никаких данных нет. На телефоне такая вёрстка рассыпается.
Как надо Для раскладки есть флексы (урок 20) и гриды (урок 21). Таблица — только для данных.
Все ячейки сделаны td, заголовков нет
Почему Таблица превращается в набор чисел без подписей. Понять её на слух невозможно.
Как надо Названия столбцов и строк — th с атрибутом scope.
Нет caption
Почему При переходе по таблицам голосовая программа зачитывает их названия. Без caption все таблицы называются одинаково — «таблица».
Как надо Первым тегом внутри table ставь caption с коротким названием.
После colspan осталось лишнее число ячеек
Почему Строка становится шире остальных, и вся сетка съезжает вправо.
Как надо Убирай ячейки, чьё место занято объединением: colspan="2" — минус одна ячейка в строке.
- Ячейка-заголовок th
- Ячейка, подписывающая строку или столбец. С
scopeсвязывает данные с названием. - Область действия scope
- Атрибут
th:col— заголовок столбца,row— строки. - Подпись таблицы caption
- Название таблицы, видимое всем и зачитываемое голосовыми программами.
- Объединение ячеек colspan / rowspan
- Растягивание одной ячейки на несколько столбцов или строк.
Проверь себя
У расписания две оси: день и время. Это настоящие табличные данные. Меню — список, галерея — набор карточек.
Без <code>scope</code> голосовая программа не знает, к чему относится ячейка, и читает голые числа.
Первая ячейка заняла место двух, значит остаётся ещё одна — всего две ячейки в разметке.
По стандарту <code>caption</code> — первый ребёнок <code>table</code>. Браузер покажет его над таблицей.
Задание
Прайс с заголовками
Собери таблицу цен: подпись caption, шапка thead с двумя заголовками столбцов («Напиток» и «Цена») и тело tbody из трёх строк. В каждой строке название напитка — это th с scope="row", а цена — обычная td.
Подсказка 1
Строка тела выглядит так: <tr><th scope="row">Латте</th><td>200 ₽</td></tr>.
Подсказка 2
Не забудь добавить второй <th scope="col">Цена</th> в шапку.
Показать решение
<table> <caption>Цены на кофе</caption> <thead> <tr> <th scope="col">Напиток</th> <th scope="col">Цена</th> </tr> </thead> <tbody> <tr><th scope="row">Эспрессо</th><td>120 ₽</td></tr> <tr><th scope="row">Капучино</th><td>190 ₽</td></tr> <tr><th scope="row">Раф</th><td>210 ₽</td></tr> </tbody></table>table { border-collapse: collapse; }th, td { padding: 8px 12px; border-bottom: 1px solid #ddd; text-align: left; }