Олег Марков
Подвал таблицы HTML tfoot
Введение
Подвал таблицы в HTML — это элемент <tfoot>, который часто игнорируют или заменяют обычными строками в <tbody>. В результате таблица теряет в удобстве, доступности и управляемости. Особенно это заметно, когда вы работаете с большими таблицами, итоговыми строками и фиксированными шапками/подвалами.
Здесь мы подробно разберем, как устроен <tfoot>, чем он полезен и как его правильно использовать. Смотрите, я покажу вам, как с помощью подвала таблицы можно:
- удобно показывать итоги и суммы;
- улучшить семантику таблицы;
- повысить доступность для экранных читалок;
- упростить работу с таблицей через CSS и JavaScript;
- подготовить таблицу к адаптивной вёрстке.
Теперь давайте постепенно пройтись по всем возможностям <tfoot> и увидеть, как вы можете применять его в реальных проектах.
Что такое <tfoot> и зачем он нужен
Семантическая роль <tfoot>
Элемент <tfoot> — это контейнер для строк подвала таблицы. В нём обычно размещают:
- итоговые суммы;
- средние значения;
- примечания по данным;
- пояснения к столбцам;
- блоки с общей статистикой.
Семантически таблица с <thead>, <tbody> и <tfoot> выглядит так:
<thead>— заголовок таблицы;<tbody>— основное тело с данными;<tfoot>— подвал с итогами и пояснениями.
Браузер и вспомогательные технологии (например, экранные читалки) понимают эту структуру и могут корректно её интерпретировать. Это важно для доступности и для правильного поведения при прокрутке или печати.
Базовый пример структуры таблицы с <tfoot>
Смотрите, я размещаю пример, чтобы вам было проще понять стандартную структуру:
<table>
<caption>Отчет по продажам за месяц</caption>
<thead>
<tr>
<th>Товар</th> <!-- Заголовок столбца "Товар" -->
<th>Количество</th> <!-- Заголовок столбца "Количество" -->
<th>Цена</th> <!-- Заголовок столбца "Цена" -->
<th>Сумма</th> <!-- Заголовок столбца "Сумма" -->
</tr>
</thead>
<tbody>
<tr>
<td>Ноутбук</td> <!-- Строка с данными по первому товару -->
<td>3</td>
<td>70000</td>
<td>210000</td>
</tr>
<tr>
<td>Монитор</td>
<td>5</td>
<td>15000</td>
<td>75000</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="3">Итого</th> <!-- Ячейка подвала с текстом "Итого" -->
<th>285000</th> <!-- Итоговая сумма по таблице -->
</tr>
</tfoot>
</table>Как видите, <tfoot> здесь отделяет итоговую строку от основных данных. Это делает структуру более понятной и для человека, и для браузера.
Важная особенность порядка элементов
В спецификации HTML допускается, что <tfoot> может быть размещён в разметке до <tbody>. Исторически это делалось для того, чтобы браузер мог сначала отрисовать заголовок и подвал, а затем загружать тело таблицы (например, потоково).
Пример:
<table>
<thead>
<tr>
<th>Товар</th>
<th>Количество</th>
<th>Цена</th>
</tr>
</thead>
<tfoot>
<tr>
<th colspan="2">Итого</th>
<th>...</th>
</tr>
</tfoot>
<tbody>
<tr>
<td>Ноутбук</td>
<td>3</td>
<td>70000</td>
</tr>
</tbody>
</table>Браузер всё равно отрисует <tfoot> внизу таблицы, даже если вы указали его перед <tbody>. Но на практике сейчас чаще используют логичный визуальный порядок — сначала <thead>, затем <tbody>, затем <tfoot> — чтобы код было проще читать и поддерживать.
Структура и вложенные элементы <tfoot>
Допустимые элементы внутри <tfoot>
Внутри <tfoot> вы можете размещать:
- одну или несколько строк
<tr>; - внутри каждой строки —
<td>или<th>.
Часто в подвале используют <th>, поскольку это логически «заголовочные» ячейки для итогов или комментариев. Но это не обязательное правило — вы можете использовать и обычные ячейки <td>, если вам так удобнее по смыслу.
Давайте разберемся на примере:
<tfoot>
<tr>
<th rowspan="2">Итого</th> <!-- Заголовочная ячейка для двух строк -->
<td>Сумма по количеству</td>
<td>8</td>
</tr>
<tr>
<td>Общая стоимость</td>
<td>285000</td>
</tr>
</tfoot>Здесь:
- первая ячейка
<th>объединяет две строки (rowspan="2"); - остальные ячейки —
<td>, потому что это просто данные (описание и значение).
Можно ли использовать несколько <tfoot>?
По спецификации HTML допустим только один <tfoot> внутри <table>. Если вы попытаетесь написать несколько подвалов, браузер, скорее всего, автоматически исправит структуру, но результат может отличаться от ожидаемого.
Поэтому правило простое: один <table> — один <tfoot>.
Если вам нужно логически разделить подвал на несколько секций (например, «Итоги по категории», «Общие итоги»), лучше сделать это с помощью нескольких строк <tr> внутри одного <tfoot>, а не создавать несколько <tfoot>.
Пример:
<tfoot>
<tr>
<th colspan="3">Итого по технике</th>
<th>250000</th>
</tr>
<tr>
<th colspan="3">Итого по аксессуарам</th>
<th>35000</th>
</tr>
<tr>
<th colspan="3">Общий итог</th>
<th>285000</th>
</tr>
</tfoot>Зачем использовать <tfoot>, если можно сделать обычную строку
Семантика и доступность (a11y)
Когда вы используете <tfoot>, вы сообщаете браузеру и ассистивным технологиям, что эти строки — подвал таблицы. Экранные читалки могут:
- озвучивать, что это footer таблицы;
- позволять быстро к нему перейти;
- корректно связывать заголовки
<th>с данными.
Если же вы просто добавите «строку с итогами» в <tbody>, для машины это будет обычная строка с данными, и смысловая структура таблицы будет менее ясной.
Управление стилями через CSS
С <tfoot> вы можете легко задавать отдельные стили для подвала:
table tfoot {
background-color: #f5f5f5; /* Отдельный фон для подвала */
font-weight: bold; /* Жирный шрифт для выделения итогов */
}
table tfoot th,
table tfoot td {
border-top: 2px solid #000; /* Линия, отделяющая подвал от тела */
}Обратите внимание, как этот фрагмент кода решает задачу: вам не нужно добавлять отдельные классы для каждой итоговой строки — достаточно стилизовать сам <tfoot>.
Логическая организация кода
Если у вас большая таблица с десятками или сотнями строк, размещение итогов внутри <tfoot> помогает:
- визуально отделить данные от итогов;
- упростить поддержку;
- ускорить поиск нужного участка кода.
Вместо того чтобы искать «где же там внизу тела таблицы строка с Итого», вы сразу переходите к блоку <tfoot>.
Поведение при печати и прокрутке
Некоторые браузеры и таблицы стилей для печати (@media print) могут использовать <thead> и <tfoot> для повторения заголовков и подвалов на каждой странице при длинной таблице. Это поведение не всегда идеально кроссбраузерно, но именно использование <tfoot> повышает шансы на корректную печать.
Кроме того, при реализации фиксированных шапок и подвалов через CSS или JavaScript (например, в админках) проще опираться на структурные элементы <thead> и <tfoot>, а не на произвольные строки.
Использование <tfoot> с CSS
Базовая стилизация подвала
Давайте посмотрим, что происходит в следующем примере — здесь мы стилизуем подвал отдельно от тела таблицы:
<table class="report">
<thead>
<tr>
<th>Товар</th>
<th>Количество</th>
<th>Цена</th>
<th>Сумма</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ноутбук</td>
<td>3</td>
<td>70000</td>
<td>210000</td>
</tr>
<tr>
<td>Монитор</td>
<td>5</td>
<td>15000</td>
<td>75000</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="3">Итого</th>
<th>285000</th>
</tr>
</tfoot>
</table>.report {
border-collapse: collapse; /* Объединяем границы ячеек */
width: 100%; /* Таблица на всю ширину контейнера */
}
.report th,
.report td {
border: 1px solid #ccc; /* Общая рамка для всех ячеек */
padding: 8px 12px; /* Отступы внутри ячеек */
text-align: right; /* Выравнивание чисел по правому краю */
}
.report thead th {
background-color: #f0f0f0; /* Фон для заголовков */
text-align: left; /* Текст заголовков слева */
}
.report tfoot {
background-color: #fafafa; /* Светлый фон для подвала */
}
.report tfoot th {
text-align: right; /* Выравниваем текст "Итого" по правому краю */
border-top: 2px solid #000; /* Более толстая верхняя граница */
}Здесь вы видите, что стили могут отличаться для заголовка, тела и подвала. Это удобно, когда вы хотите визуально отделить итоги от основного массива данных.
Закреплённый подвал с помощью position: sticky
Иногда полезно, чтобы подвал «прилипал» к нижней части видимой области при прокрутке таблицы. Например, если у вас много строк, а в подвале — общая сумма или кнопки действия.
Покажу вам, как это реализовано на практике (обратите внимание, что поведение может отличаться в разных браузерах и для сложных случаев потребуется дополнительный JS):
<div class="table-wrapper">
<table class="sticky-footer-table">
<thead>
<tr>
<th>Товар</th>
<th>Количество</th>
<th>Цена</th>
<th>Сумма</th>
</tr>
</thead>
<tbody>
<!-- Здесь может быть много строк с данными -->
<tr>
<td>Ноутбук</td>
<td>3</td>
<td>70000</td>
<td>210000</td>
</tr>
<tr>
<td>Монитор</td>
<td>5</td>
<td>15000</td>
<td>75000</td>
</tr>
<!-- ... -->
</tbody>
<tfoot>
<tr>
<th colspan="3">Итого</th>
<th>285000</th>
</tr>
</tfoot>
</table>
</div>.table-wrapper {
max-height: 300px; /* Ограничиваем высоту контейнера */
overflow-y: auto; /* Включаем вертикальную прокрутку */
}
.sticky-footer-table {
border-collapse: collapse;
width: 100%;
}
.sticky-footer-table th,
.sticky-footer-table td {
border: 1px solid #ccc;
padding: 8px;
}
.sticky-footer-table tfoot th,
.sticky-footer-table tfoot td {
position: sticky; /* Делаем ячейки "липкими" */
bottom: 0; /* Прилипают к низу контейнера */
background: #fff; /* Фон, чтобы текст не сливался с содержимым под ним */
z-index: 1; /* Поднимаем над другими ячейками */
}Здесь важный момент: position: sticky мы применяем к ячейкам подвала. Внутренний контейнер с прокруткой (.table-wrapper) позволяет подвалу «залипать» внизу видимой области этого контейнера.
Стили для адаптивных таблиц
В адаптивной вёрстке продвинутые таблицы нередко превращаются в блочные карточки на маленьких экранах. В таких сценариях <tfoot> можно визуально сдвинуть, например, под заголовок или в конец карточки. Но при этом важно сохранить структуру: в HTML всё равно остаётся <tfoot> как часть таблицы.
Упрощенный пример подхода:
@media (max-width: 600px) {
table.responsive,
table.responsive thead,
table.responsive tbody,
table.responsive tfoot,
table.responsive tr,
table.responsive th,
table.responsive td {
display: block; /* Превращаем таблицу и её части в блоки */
}
table.responsive tfoot {
order: 2; /* Можно управлять порядком через flex или grid обёртку */
}
}На практике для сложных адаптивных таблиц обычно используют дополнительные обёртки и JS, но <tfoot> остаётся полезной семантической опорой.
Использование <tfoot> с JavaScript
Поиск и обновление итогов
Обычно подвал используют для отображения итоговых значений, например суммы по столбцу. Давайте разберемся на примере, как вы можете автоматически пересчитывать «Итого» при изменении данных.
HTML:
<table id="orders">
<thead>
<tr>
<th>Товар</th>
<th>Количество</th>
<th>Цена</th>
<th>Сумма</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ноутбук</td>
<td class="qty">3</td>
<td class="price">70000</td>
<td class="total">210000</td>
</tr>
<tr>
<td>Монитор</td>
<td class="qty">5</td>
<td class="price">15000</td>
<td class="total">75000</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="3">Итого</th>
<th id="grandTotal">285000</th>
</tr>
</tfoot>
</table>
<button id="recalcBtn">Пересчитать итоги</button>JavaScript:
// Функция пересчёта итогов по столбцу "Сумма"
function recalcTotals() {
const table = document.getElementById('orders'); // Находим таблицу
const bodyRows = table.tBodies[0].rows; // Получаем все строки тела таблицы
let sum = 0;
// Проходим по всем строкам и суммируем значения в ячейках с классом "total"
for (let row of bodyRows) {
const totalCell = row.querySelector('.total'); // Находим ячейку "Сумма" в текущей строке
if (!totalCell) continue;
const value = parseFloat(totalCell.textContent); // Преобразуем текст в число
if (!isNaN(value)) {
sum += value; // Прибавляем к общей сумме
}
}
// Обновляем ячейку в подвале таблицы
const grandTotalCell = document.getElementById('grandTotal');
grandTotalCell.textContent = sum.toString(); // Записываем итоговую сумму в подвал
}
// Навешиваем обработчик на кнопку "Пересчитать итоги"
document.getElementById('recalcBtn').addEventListener('click', recalcTotals);Здесь вы видите, что:
<tfoot>нам даёт понятную точку, куда выводить результат (#grandTotal);- доступ к телу таблицы осуществляется через
table.tBodies[0]; - подвал при этом не вмешивается в логику обхода строк с данными.
Динамическое создание <tfoot>
Иногда таблица строится динамически из данных, и вам нужно программно добавить <tfoot>. Покажу вам, как это выглядит в коде:
// Функция создания подвала с итоговой суммой
function createTableFooter(table, total) {
// Если подвал уже есть - удаляем его, чтобы не дублировать
if (table.tFoot) {
table.removeChild(table.tFoot); // Удаляем существующий <tfoot>
}
const tfoot = table.createTFoot(); // Создаём новый элемент <tfoot>
const row = tfoot.insertRow(); // Вставляем строку в подвал
const labelCell = document.createElement('th'); // Создаём заголовочную ячейку
labelCell.colSpan = 3; // Объединяем три столбца
labelCell.textContent = 'Итого'; // Текст в ячейке
row.appendChild(labelCell); // Добавляем ячейку в строку
const totalCell = document.createElement('th'); // Создаём ячейку с итоговым значением
totalCell.textContent = total.toString(); // Записываем итоговое значение
row.appendChild(totalCell); // Добавляем ячейку в строку
}
// Пример использования функции
const table = document.getElementById('orders');
createTableFooter(table, 285000);Обратите внимание на метод table.createTFoot() — это стандартный способ создать <tfoot> через DOM API, и он автоматически добавит элемент в таблицу.
Работа с несколькими секциями <tbody> и одним <tfoot>
В больших таблицах иногда используют несколько <tbody> (например, по категориям), но подвал по-прежнему один. С точки зрения JavaScript это не создаёт проблем: вы можете обойти все тела таблицы и подсчитать итог.
Пример обхода всех tbody:
// Суммируем значения в ячейках с классом "total" во всех <tbody>
function calculateGrandTotal(table) {
let sum = 0;
// Перебираем все тела таблицы
for (let tbody of table.tBodies) {
for (let row of tbody.rows) {
const cell = row.querySelector('.total'); // Ячейка суммы в текущей строке
if (!cell) continue;
const value = parseFloat(cell.textContent);
if (!isNaN(value)) {
sum += value; // Прибавляем значение к общей сумме
}
}
}
return sum;
}Затем вы можете записать полученную сумму в <tfoot>, как мы делали выше.
Практические паттерны использования <tfoot>
Итоги по нескольким столбцам
Частый сценарий — когда в подвале нужно показать итоги не только по одной колонке, а сразу по нескольким. Давайте посмотрим, что происходит, если, например, у нас есть:
- количество товаров;
- общая сумма;
- средняя цена.
HTML:
<table id="analytics">
<thead>
<tr>
<th>Товар</th>
<th>Количество</th>
<th>Цена</th>
<th>Сумма</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ноутбук</td>
<td class="qty">3</td>
<td class="price">70000</td>
<td class="total">210000</td>
</tr>
<tr>
<td>Монитор</td>
<td class="qty">5</td>
<td class="price">15000</td>
<td class="total">75000</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Итого</th>
<th id="sumQty">8</th>
<th id="avgPrice">...</th>
<th id="sumTotal">285000</th>
</tr>
</tfoot>
</table>JS:
// Пересчитываем суммарное количество, общую сумму и среднюю цену
function recalcAnalytics() {
const table = document.getElementById('analytics');
let totalQty = 0;
let totalSum = 0;
let itemsCount = 0;
for (let row of table.tBodies[0].rows) {
const qtyCell = row.querySelector('.qty'); // Ячейка с количеством
const totalCell = row.querySelector('.total'); // Ячейка с суммой
if (!qtyCell || !totalCell) continue;
const qty = parseFloat(qtyCell.textContent);
const total = parseFloat(totalCell.textContent);
if (!isNaN(qty)) {
totalQty += qty; // Суммируем количество
}
if (!isNaN(total)) {
totalSum += total; // Суммируем стоимость
}
itemsCount++; // Считаем количество строк
}
const avgPrice = itemsCount > 0 ? totalSum / totalQty : 0; // Средняя цена за единицу
// Обновляем ячейки в подвале
document.getElementById('sumQty').textContent = totalQty.toString();
document.getElementById('sumTotal').textContent = totalSum.toString();
document.getElementById('avgPrice').textContent = avgPrice.toFixed(2); // Округляем до двух знаков
}Здесь <tfoot> служит удобным местом для итоговых метрик по таблице, а JavaScript заполняет их при загрузке или изменении данных.
Комбинированный подвал — итоги и примечания
Иногда нужно в подвале показать не только итоги, но и сноски или пояснения (например, валюту, налог, источник данных). В таком случае вы можете использовать несколько строк <tr> внутри <tfoot>:
<tfoot>
<tr>
<th colspan="3">Итого без НДС</th>
<th>250000</th>
</tr>
<tr>
<th colspan="3">НДС 14%</th>
<th>35000</th>
</tr>
<tr>
<th colspan="3">Итого с НДС</th>
<th>285000</th>
</tr>
<tr>
<td colspan="4">
* Все цены указаны в рублях по курсу на дату формирования отчета.
</td>
</tr>
</tfoot>Такой подход позволяет держать в одном месте и расчёты, и пояснения, что упрощает чтение кода и поддержки.
Подвал для действий (кнопки, фильтры, пагинация)
Ещё один интересный паттерн — использовать <tfoot> не только для числовых итогов, но и для элементов управления:
- кнопки «Добавить строку», «Сохранить»;
- фильтры по итогам;
- переключатели страниц (пагинация) для табличных данных.
Пример:
<table class="editable">
<thead>
<tr>
<th>Товар</th>
<th>Количество</th>
<th>Цена</th>
</tr>
</thead>
<tbody id="itemsBody">
<!-- Строки с данными будут добавляться динамически -->
</tbody>
<tfoot>
<tr>
<td colspan="3">
<button id="addRowBtn">Добавить строку</button>
<!-- Кнопка добавления новой строки -->
<button id="saveTableBtn">Сохранить</button>
<!-- Кнопка сохранения таблицы -->
</td>
</tr>
</tfoot>
</table>JS:
// Добавляем новую пустую строку в таблицу
document.getElementById('addRowBtn').addEventListener('click', () => {
const tbody = document.getElementById('itemsBody'); // Находим тело таблицы
const row = tbody.insertRow(); // Вставляем новую строку
// Создаём три ячейки: Товар, Количество, Цена
for (let i = 0; i < 3; i++) {
const cell = row.insertCell();
const input = document.createElement('input'); // Поле ввода для редактирования
input.type = 'text';
cell.appendChild(input); // Добавляем поле ввода в ячейку
}
});Здесь <tfoot> по смыслу становится «панелью управления» для таблицы. Это вполне допустимо, если вы сохраняете логику: это элементы, относящиеся к всей таблице целиком.
Особенности доступности и ARIA с <tfoot>
Использование <th scope> в подвале
Чтобы улучшить доступность, полезно использовать атрибут scope в <th>. В подвале часто уместно указывать scope="row" или scope="col".
Пример:
<tfoot>
<tr>
<th scope="row" colspan="3">Итого</th>
<!-- scope="row" говорит, что эта ячейка описывает строку -->
<th scope="col">285000</th>
<!-- scope="col" можно использовать, если это заголовок столбца итогов -->
</tr>
</tfoot>Экранные читалки за счёт scope лучше понимают взаимосвязь заголовков и данных.
Роль таблицы и регионов
В большинстве случаев вам не нужно явно добавлять ARIA-атрибуты к <tfoot>: браузеры уже знают, что это подвал таблицы. Но иногда можно добавить дополнительные подсказки атрибутами aria-label или aria-describedby, если подвал содержит что-то нетипичное (например, сложные пояснения).
Пример:
<tfoot aria-label="Итоговые значения по таблице продаж">
<tr>
<th colspan="3">Итого</th>
<th>285000</th>
</tr>
</tfoot>Здесь мы даём дополнительное текстовое описание для пользователей экранных читалок.
Нюансы вёрстки и совместимости
Один <tfoot> на таблицу
Как уже упоминалось, помните ограничение: в таблице может быть только один <tfoot>. Если при генерации HTML вы случайно создадите несколько, могут возникнуть:
- странное поведение браузера при перестроении DOM;
- проблемы со стилями (браузер может переместить подвал);
- непредсказуемое поведение в скринридерах.
Поэтому при генерации HTML на сервере или в JS-шаблонах всегда закладывайте только одну секцию <tfoot>.
Взаимодействие с colspan и rowspan
В подвале вы можете объединять ячейки по строкам (rowspan) и столбцам (colspan). Главное — следить за тем, чтобы итоговая структура совпадала с количеством видимых столбцов в таблице.
Типичная ошибка — неправильное количество колонок в <tfoot>, что ломает визуальное выравнивание.
Хорошая практика:
- убедиться, что сумма
colspanв строке подвала равна общему количеству логических колонок; - при изменении структуры заголовка или тела — не забывать обновлять и
tfoot.
Печать и многократный повтор подвала
Некоторые движки печати в браузерах могут пытаться повторять <thead> и <tfoot> на каждой странице. Поведение отличается:
- в одних браузерах повторяется только
<thead>; - в других — и шапка, и подвал;
- в некоторых случаях подвал появляется только в самом конце.
Если печатная форма для вас критична, имеет смысл протестировать:
- как таблица печатается в основных браузерах;
- нужны ли дополнительные стили
@media print(например, принудительное скрытие подвала или его упрощение).
Пример печатных стилей:
@media print {
table tfoot {
font-size: 12px; /* Можно уменьшить размер текста для печати */
}
}Заключение
Подвал таблицы HTML через элемент <tfoot> — это не просто «ещё одна строка внизу». Это:
- семантический контейнер для итогов, пояснений и действий;
- точка опоры для CSS (отдельные стили, фиксированный подвал);
- удобный ориентир для JavaScript при подсчётах и манипуляции таблицей;
- важный элемент для доступности и корректной структуры.
Используя <tfoot> вместе с <thead> и <tbody>, вы получаете структурированную, читабельную и расширяемую таблицу. Это особенно ценно в реальных проектах, где таблицы часто становятся центром интерфейса — от админок до аналитических панелей.
Если вы сейчас верстаете таблицу, в которой есть «итоги», «примечания внизу» или панель действий, имеет смысл оформить их в <tfoot>. Так вы сделаете код понятнее, а поведение таблицы — предсказуемее и более гибким.
Частозадаваемые технические вопросы по теме и ответы
1. Как сделать так, чтобы <tfoot> всегда отображался под tbody, даже если я добавляю строки динамически?
Проверьте порядок элементов внутри <table>. Если вы добавляете строки через appendChild или innerHTML напрямую в конец таблицы, новые узлы могут оказаться после <tfoot>. Решение — всегда работать с tbody:
const tbody = table.tBodies[0]; // Находим тело таблицы
const row = tbody.insertRow(); // Добавляем строку только в <tbody>Таким образом <tfoot> остаётся последним дочерним элементом таблицы по структуре и всегда визуально находится внизу.
2. Почему position: sticky в <tfoot> работает не во всех браузерах или ломает верстку?
Причины обычно две:
position: stickyне работает дляdisplay: table-footer-group. Ячейки<th>и<td>внутри<tfoot>могут вести себя нестабильно. Решение — применятьposition: stickyнепосредственно к ячейкам, а не к<tfoot>.Липкий элемент должен находиться внутри контейнера с прокруткой (у которого
overflowзадан). Убедитесь, что прокрутка включена на родителе таблицы, а не на всей странице.
3. Можно ли программно переместить строку из <tbody> в <tfoot>?
Да. Это обычная операция переноса DOM-элемента. Например:
const table = document.querySelector('table');
const lastBodyRow = table.tBodies[0].rows[table.tBodies[0].rows.length - 1];
const tfoot = table.tFoot || table.createTFoot(); // Получаем или создаём <tfoot>
tfoot.appendChild(lastBodyRow); // Перемещаем строку в подвалСтрока физически перемещается из тела в подвал, и браузер отрисует её внизу таблицы.
4. Как скрыть <tfoot> только на мобильных устройствах, но оставить его в DOM?
Используйте медиа-запросы и display: none:
@media (max-width: 600px) {
table tfoot {
display: none; /* Скрываем подвал только визуально */
}
}Подвал остаётся в DOM и доступен для JavaScript, но не отображается на экране с небольшой шириной.
5. Можно ли использовать <tfoot> внутри <table> с role="presentation" или для чисто визуальных таблиц?
Технически можно, но смысл <tfoot> в этом случае теряется. Если таблица служит только для визуальной сетки и вы помечаете её role="presentation", ассистивные технологии игнорируют её как таблицу. В таких случаях <tfoot> не даёт преимуществ по доступности, и лучше использовать обычные блочные элементы (например, div) для разметки подвала.
Постройте личный план изучения Html до уровня Middle — бесплатно!
Html — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Все гайды по Html
Лучшие курсы по теме

HTML и CSS
Антон Ларичев
TypeScript с нуля
Антон Ларичев