иконка discount

Скидка 15% по промокоду

кибер понедельник до 01.12иконка discount
CYBER2025
логотип PurpleSchool
логотип PurpleSchool

Подвал таблицы 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> работает не во всех браузерах или ломает верстку?

Причины обычно две:

  1. position: sticky не работает для display: table-footer-group. Ячейки <th> и <td> внутри <tfoot> могут вести себя нестабильно. Решение — применять position: sticky непосредственно к ячейкам, а не к <tfoot>.

  2. Липкий элемент должен находиться внутри контейнера с прокруткой (у которого 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 th - полное руководствоЯчейка таблицы HTML td - полное руководство по верстке таблицСтрелочка вправо

Постройте личный план изучения Html до уровня Middle — бесплатно!

Html — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Все гайды по Html

Тег section в HTML - семантическая разметка структуры страницыТег nav в HTML - полное руководство по семантической навигацииТег main в HTML - подробное руководство по использованиюТег header в HTML - полное практическое руководствоТег footer в HTML - назначение семантика и практические примерыТег figure в HTML - как правильно оформлять иллюстрации и подписиТег figcaption в HTML - подробное руководство с примерамиТег aside в HTML - назначение правильная семантика и примеры
Текстовая область HTML textarea - практическое руководствоВыпадающий список HTML select - полное руководство для разработчиковОпция списка HTML option - как работает и как правильно использоватьАтрибут method в HTML - как правильно отправлять данные формыЗаголовок группы HTML legend - как правильно использовать и оформлятьТег input в HTML - типы атрибуты валидация и примерыТег формы form в HTMLГруппа полей HTML fieldsetАтрибут action в HTML - как правильно задавать адрес отправки формы
Открыть базу знаний

Лучшие курсы по теме

изображение курса

HTML и CSS

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

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