Можем ли мы иметь несколько <tbody> в одной <таблице>?

594

Можем ли мы иметь несколько <tbody>тегов в одном <table>? Если да, то в каких случаях мы должны использовать несколько <tbody>тегов?

Джитендра Вьяс
источник

Ответы:

710

Да, вы можете использовать их, например, я использую их для упрощения стилизации групп данных, например так:

thead th { width: 100px; border-bottom: solid 1px #ddd; font-weight: bold; }
tbody:nth-child(odd) { background: #f5f5f5;  border: solid 1px #ddd; }
tbody:nth-child(even) { background: #e5e5e5;  border: solid 1px #ddd; }
<table>
    <thead>
        <tr><th>Customer</th><th>Order</th><th>Month</th></tr>
    </thead>
    <tbody>
        <tr><td>Customer 1</td><td>#1</td><td>January</td></tr>
        <tr><td>Customer 1</td><td>#2</td><td>April</td></tr>
        <tr><td>Customer 1</td><td>#3</td><td>March</td></tr>
    </tbody>
    <tbody>
        <tr><td>Customer 2</td><td>#1</td><td>January</td></tr>
        <tr><td>Customer 2</td><td>#2</td><td>April</td></tr>
        <tr><td>Customer 2</td><td>#3</td><td>March</td></tr>
    </tbody>
    <tbody>
        <tr><td>Customer 3</td><td>#1</td><td>January</td></tr>
        <tr><td>Customer 3</td><td>#2</td><td>April</td></tr>
        <tr><td>Customer 3</td><td>#3</td><td>March</td></tr>
    </tbody>
</table>

Вы можете посмотреть пример здесь . Это будет работать только в новых браузерах, но это то, что я поддерживаю в моем текущем приложении: вы можете использовать группирование для JavaScript и т. Д. Главное, это удобный способ визуально сгруппировать строки, чтобы сделать данные намного более читабельными , Конечно, есть и другие варианты использования, но, насколько это применимо, этот пример является наиболее распространенным для меня.

Ник Крейвер
источник
6
хорошо, спасибо за отличный ответ. Имеет ли значение для программы чтения с экрана, один tbodyили несколько?
Джитендра Вьяс
1
@ metal-gear-solid - По моему опыту, они справляются с ними хорошо, например: как будто они один <tbody>. Когда вы начинаете вкладывать таблицы, это обычно создает реальные проблемы с навигацией для программы чтения с экрана.
Ник Крейвер
10
@metal: нет, есть семантическая разница - несколько <tbody>элементов описывают отдельные группы в таблице, как было объяснено в ответе. Также я должен добавить, что в целом лучше ориентироваться на ячейки для фона, поэтому CSS должен быть, например,tbody:nth-child(odd) td { background: #f5f5f5; }
DisgruntledGoat
4
Какое определение для "Более новые браузеры"?
Тим Даун
8
@TimDown - когда я сказал «более новые браузеры», он имел в виду только :nth-child()использование CSS для связанной демонстрации, множественное число <tbody>будет работать в любом браузере.
Ник Крейвер
298

Да. От DTD

<!ELEMENT table
     (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>

Так что ожидается один или несколько. Затем он продолжает говорить

Используйте несколько секций tbody, когда нужны правила между группами строк таблицы.

Мартин Смит
источник
12
Что касается спецификации HTML5, это немного меняется, но фундаментальное «да, с несколькими tbodyэлементами все в порядке) остается. В частности, теперь вам разрешено помещать один tfootэлемент после того, tbodyесли вам нравится . (Они аккуратно обошли стороной аспект DTD» говоря, что они не предоставляют один .) :-)
TJ Crowder
5
Спасибо за этот ответ. Ссылка на спецификации - это ответ № 1 в моей книге.
KernelCurry
1
Так что ожидается один или несколько. Это неправильно, это может быть набор значений, <tr>поэтому он также может быть равен нулю (т. Е. Tbody или tr означает, что это может быть просто tr, а не tbody.)
Алексис Уилк
@AlexisWilke это верно в соответствии со спецификациями: начальный тег TBODY всегда требуется, кроме случаев, когда таблица содержит только одно тело таблицы и не содержит ни заголовков, ни разделов таблицы
Gecko IT
14

Проблема Мартина Столяра вызвана неправильным пониманием <caption>тега.

<caption>Тег определяет заголовок таблицы.

<caption>Тег должен быть первым потомком <table>тега.

Вы можете указать только одну подпись к таблице.

Также обратите внимание, что scopeатрибут должен быть размещен на <th>элементе, а не на <tr>элементе.

Правильный способ написания таблицы из нескольких заголовков с несколькими заголовками будет выглядеть примерно так:

<table id="dinner_table">
    <caption>This is the only correct place to put a caption.</caption>
    <tbody>
        <tr class="header">
            <th colspan="2" scope="col">First Half of Table (British Dinner)</th>
        </tr>
        <tr>
            <th scope="row">1</th>
            <td>Fish</td>
        </tr>
        <tr>
            <th scope="row">2</th>
            <td>Chips</td>
        </tr>
        <tr>
            <th scope="row">3</th>
            <td>Peas</td>
        </tr>
        <tr>
            <th scope="row">4</th>
            <td>Gravy</td>
        </tr>
    </tbody>
    <tbody>
        <tr class="header">
            <th colspan="2" scope="col">Second Half of Table (Italian Dinner)</th>
        </tr>
        <tr>
            <th scope="row">5</th>
            <td>Pizza</td>
        </tr>
        <tr>
            <th scope="row">6</th>
            <td>Salad</td>
        </tr>
        <tr>
            <th scope="row">7</th>
            <td>Oil</td>
        </tr>
        <tr>
            <th scope="row">8</th>
            <td>Bread</td>
        </tr>
    </tbody>
</table>

Джон Слегерс
источник
captionТег должен следовать открывающий tableтег. developer.mozilla.org/en-US/docs/Web/HTML/Element/table
Cypher
Вы правы. Я как-то неверно истолковал документы. Я исправил ошибку.
Джон Слегерс
Спецификация рекомендует использовать scope="rowgroup"(вместо col) для tbodyзаголовков. Смотрите пример .
CletusW
7

Да. Я использую их для динамического сокрытия / раскрытия соответствующей части таблицы, например, курса. А именно

<table>
  <tbody id="day1" style="display:none">
    <tr><td>session1</td><tr>
    <tr><td>session2</td><tr>
  </tbody>
  <tbody id="day2">
    <tr><td>session3</td><tr>
    <tr><td>session4</td><tr>
  </tbody>
  <tbody id="day3" style="display:none">
    <tr><td>session5</td><tr>
    <tr><td>session6</td><tr>
  </tbody>
</table>

Может быть предусмотрена кнопка для переключения между всем или только текущим днем ​​путем манипулирования телами без индивидуальной обработки множества строк.

CPslashM
источник
4

РЕДАКТИРОВАТЬ: captionтег принадлежит к таблице и, следовательно, должен существовать только один раз. Не связывайте a captionс каждым tbodyэлементом, как я:

<table>
    <caption>First Half of Table (British Dinner)</caption>
    <tbody>
        <tr><th>1</th><td>Fish</td></tr>
        <tr><th>2</th><td>Chips</td></tr>
        <tr><th>3</th><td>Pease</td></tr>
        <tr><th>4</th><td>Gravy</td></tr>
    </tbody>
    <caption>Second Half of Table (Italian Dinner)</caption>
    <tbody>
        <tr><th>5</th><td>Pizza</td></tr>
        <tr><th>6</th><td>Salad</td></tr>
        <tr><th>7</th><td>Oil</td></tr>
        <tr><th>8</th><td>Bread</td></tr>
    </tbody>
</table>

ПЛОХОЙ ПРИМЕР ВЫШЕ: НЕ КОПИРУЙТЕ

Приведенный выше пример не отображается так, как вы ожидаете, потому что запись в таком виде указывает на неправильное понимание captionтега. Вам понадобится много CSS-хаков, чтобы он правильно отображался, потому что вы будете идти против стандартов.

Я искал стандарты W3Cs для captionтега, но не смог найти явного правила, согласно которому captionв таблице должен быть только один элемент, но на самом деле это так.

Мартин Столяр
источник
3

Кроме того, если вы запустите HTML-документ с несколькими <tbody>тегами через HTML-валидатор W3C с HTML5 DOCTYPE, он успешно пройдет проверку.

Берн
источник
2

Я создал JSFiddle, где у меня есть два вложенных ng-повторения с таблицами и родительский ng-повтор на tbody. Если вы проверите любую строку в таблице, вы увидите, что есть шесть элементов tbody, то есть родительский уровень.

HTML

<div>
        <table class="table table-hover table-condensed table-striped">
            <thead>
                <tr>
                    <th>Store ID</th>
                    <th>Name</th>
                    <th>Address</th>
                    <th>City</th>
                    <th>Cost</th>
                    <th>Sales</th>
                    <th>Revenue</th>
                    <th>Employees</th>
                    <th>Employees H-sum</th>
                </tr>
            </thead>
            <tbody data-ng-repeat="storedata in storeDataModel.storedata">
                <tr id="storedata.store.storeId" class="clickableRow" title="Click to toggle collapse/expand day summaries for this store." data-ng-click="selectTableRow($index, storedata.store.storeId)">
                    <td>{{storedata.store.storeId}}</td>
                    <td>{{storedata.store.storeName}}</td>
                    <td>{{storedata.store.storeAddress}}</td>
                    <td>{{storedata.store.storeCity}}</td>
                    <td>{{storedata.data.costTotal}}</td>
                    <td>{{storedata.data.salesTotal}}</td>
                    <td>{{storedata.data.revenueTotal}}</td>
                    <td>{{storedata.data.averageEmployees}}</td>
                    <td>{{storedata.data.averageEmployeesHours}}</td>
                </tr>
                <tr data-ng-show="dayDataCollapse[$index]">
                    <td colspan="2">&nbsp;</td>
                    <td colspan="7">
                        <div>
                            <div class="pull-right">
                                <table class="table table-hover table-condensed table-striped">
                                    <thead>
                                        <tr>
                                            <th></th>
                                            <th>Date [YYYY-MM-dd]</th>
                                            <th>Cost</th>
                                            <th>Sales</th>
                                            <th>Revenue</th>
                                            <th>Employees</th>
                                            <th>Employees H-sum</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr data-ng-repeat="dayData in storeDataModel.storedata[$index].data.dayData">
                                            <td class="pullright">
                                                <button type="btn btn-small" title="Click to show transactions for this specific day..." data-ng-click=""><i class="icon-list"></i>
                                                </button>
                                            </td>
                                            <td>{{dayData.date}}</td>
                                            <td>{{dayData.cost}}</td>
                                            <td>{{dayData.sales}}</td>
                                            <td>{{dayData.revenue}}</td>
                                            <td>{{dayData.employees}}</td>
                                            <td>{{dayData.employeesHoursSum}}</td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>

(Примечание: это заполняет DOM, если у вас много данных на обоих уровнях, поэтому я работаю над директивой для извлечения данных и замены, т.е. добавление в DOM при нажатии на родительский элемент и удаление при нажатии на другой или тот же родительский элемент снова. Чтобы получить такое поведение, которое вы найдете в Prisjakt.nu , если вы прокрутите вниз до перечисленных компьютеров и щелкните по строке (не по ссылкам). Если вы сделаете это и осмотрите элементы, вы увидите, что добавлен tr и затем удаляется, если родитель нажимается снова или другой.)

Pixic
источник