Podemos ter vários <tbody> na mesma <table>?

594

Podemos ter várias <tbody>tags na mesma <table>? Se sim, então em quais cenários devemos usar várias <tbody>tags?

Jitendra Vyas
fonte

Respostas:

710

Sim, você pode usá-los, por exemplo, eu os uso para estilizar grupos de dados com mais facilidade, assim:

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>

Você pode ver um exemplo aqui . Ele funcionará apenas em navegadores mais novos, mas é isso que estou suportando no meu aplicativo atual, você pode usar o agrupamento para JavaScript etc. O principal é que é uma maneira conveniente de agrupar visualmente as linhas para tornar os dados muito mais legíveis . Existem outros usos, é claro, mas, nos exemplos aplicáveis, este é o mais comum para mim.

Nick Craver
fonte
6
ok obrigado pela ótima resposta. Importa ao leitor de tela, um tbodyou vários?
Jitendra Vyas
1
@ metal-gear-solid - Na minha experiência, eles lidam com eles muito bem, por exemplo: como se fossem um <tbody>. Quando você começa a aninhar tabelas, é isso que geralmente causa problemas reais de navegação para um leitor de tela.
Nick Craver
10
@metal: não, há uma diferença semântica - vários <tbody>elementos descrevem grupos separados na tabela, como foi explicado na resposta. Também devo acrescentar que geralmente é melhor para células-alvo para os fundos, de modo que o CSS deve ser, por exemplo,tbody:nth-child(odd) td { background: #f5f5f5; }
DisgruntledGoat
4
Qual é a definição de "navegadores mais recentes"?
Tim Baixo
8
@ TimDown - quando eu disse "navegadores mais recentes", estava apenas se referindo ao :nth-child()uso de CSS para a demonstração vinculada, o múltiplo <tbody>funcionará em qualquer navegador.
Nick Craver
298

Sim. Do DTD

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

Portanto, espera um ou mais. Em seguida, continua a dizer

Use várias seções de corpo quando forem necessárias regras entre grupos de linhas da tabela.

Martin Smith
fonte
12
Como na especificação do HTML5, isso muda um pouco, mas o fundamental "sim, vários tbodyelementos são bons) permanece. Especificamente, agora você pode colocar o tfootelemento após o tbodyque quiser . dizendo que eles não fornecem um ) :-).
TJ Crowder
5
Obrigado por esta resposta. Referenciar especificações é a resposta nº 1 do meu livro.
KernelCurry
1
Portanto, espera um ou mais. Isso é errado, pode ser um conjunto de <tr>modo que também poderia ser zero (ou seja, uma tbody ou um meio tr Poderia ser apenas um tr e nenhum tbody.)
Alexis Wilke
@AlexisWilke isso é verdade de acordo com as especificações: A tag TBODY início é sempre necessária, exceto quando a tabela contém apenas um corpo mesa e há seções de cabeça de mesa ou de pé
Gecko TI
14

O problema de Martin Joiner é causado por um mal-entendido da <caption>tag.

A <caption>tag define uma legenda da tabela.

A <caption>tag deve ser o primeiro filho da <table>tag.

Você pode especificar apenas uma legenda por tabela.

Além disso, observe que o scopeatributo deve ser colocado em um <th>elemento e não em um <tr>elemento.

A maneira correta de escrever uma tabela com vários cabeçalhos e vários corpos seria algo como isto:

<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>

John Slegers
fonte
A captiontag deve seguir a tabletag de abertura . developer.mozilla.org/pt-BR/docs/Web/HTML/Element/table
Cypher
Você está certo. De alguma forma, interpretei mal os documentos. Corrigi o erro.
precisa saber é o seguinte
Spec recomenda o uso scope="rowgroup"(em vez de col) para os tbodycabeçalhos. Veja o exemplo .
CletusW 12/02
7

Sim. Eu os uso para ocultar / revelar dinamicamente a parte relevante de uma tabela, por exemplo, um curso. Viz.

<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>

Um botão pode ser fornecido para alternar entre tudo ou apenas o dia atual, manipulando tbodies sem processar muitas linhas individualmente.

CPslashM
fonte
4

EDIT: A captiontag pertence à tabela e, portanto, só deve existir uma vez. Não associe a captiona cada tbodyelemento como eu fiz:

<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>

MAU EXEMPLO ACIMA: NÃO COPIE

O exemplo acima não é renderizado como seria de esperar, porque escrever assim indica um mal-entendido da captiontag. Você precisaria de muitos hacks CSS para torná-lo renderizado corretamente, porque você iria contra os padrões.

Procurei os padrões W3Cs na captiontag, mas não consegui encontrar uma regra explícita que afirma que deve haver apenas um captionelemento por tabela, mas esse é realmente o caso.

Martin Joiner
fonte
3

Além disso, se você executar um documento HTML com várias <tbody>tags através do Validador HTML do W3C , com um DOCTYPE HTML5, ele será validado com êxito.

Berna
fonte
2

Criei um JSFiddle em que tenho duas repetições ng aninhadas com tabelas e a repetição ng pai em tbody. Se você inspecionar qualquer linha da tabela, verá seis elementos do corpo, ou seja, o nível pai.

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>

(Observação: isso preenche o DOM se você tiver muitos dados nos dois níveis, portanto, estou trabalhando em uma diretiva para buscar dados e substituir, ou seja, adicionando ao DOM ao clicar em pai e removendo quando outro é clicado ou no mesmo pai. Para obter o tipo de comportamento encontrado no Prisjakt.nu , se você rolar para baixo até os computadores listados e clicar na linha (não nos links). Se você fizer isso e inspecionar elementos, verá que um tr é adicionado e removido, se o pai for clicado novamente ou em outro.)

Pixic
fonte