Pouvons-nous avoir plusieurs <tbody> dans la même <table>?

594

Pouvons-nous avoir plusieurs <tbody>balises en même temps <table>? Si oui, dans quels scénarios devrions-nous utiliser plusieurs <tbody>balises?

Jitendra Vyas
la source

Réponses:

710

Oui, vous pouvez les utiliser, par exemple je les utilise pour styliser plus facilement des groupes de données, comme ceci:

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>

Vous pouvez voir un exemple ici . Cela ne fonctionnera que dans les nouveaux navigateurs, mais c'est ce que je soutiens dans mon application actuelle, vous pouvez utiliser le regroupement pour JavaScript, etc. L'essentiel est que c'est un moyen pratique de grouper visuellement les lignes pour rendre les données beaucoup plus lisibles . Il y a bien sûr d'autres utilisations, mais en ce qui concerne les exemples applicables, celui-ci est le plus courant pour moi.

Nick Craver
la source
6
ok merci pour la bonne réponse. Est-ce important de filtrer le lecteur, un tbodyou plusieurs?
Jitendra Vyas
1
@ metal-gear-solid - D'après mon expérience, ils les gèrent bien, par exemple: comme s'ils n'en faisaient qu'un <tbody>. Lorsque vous commencez à imbriquer des tables, c'est ce qui pose généralement de réels problèmes de navigation pour un lecteur d'écran.
Nick Craver
10
@metal: non, il y a une différence sémantique - plusieurs <tbody>éléments décrivent des groupes séparés dans le tableau, comme cela a été expliqué dans la réponse. Je dois également ajouter qu'il est généralement préférable de cibler les cellules pour les arrière-plans, de sorte que le CSS devrait être, par exemple,tbody:nth-child(odd) td { background: #f5f5f5; }
DisgruntledGoat
4
Quelle est la définition de "nouveaux navigateurs"?
Tim Down
8
@TimDown - lorsque j'ai dit "nouveaux navigateurs", il ne faisait référence qu'à l' :nth-child()utilisation de CSS pour la démonstration liée, le multiple <tbody>fonctionnera dans n'importe quel navigateur.
Nick Craver
298

Oui. De la DTD

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

Il attend donc un ou plusieurs. Il poursuit en disant

Utilisez plusieurs sections tbody lorsque des règles sont nécessaires entre des groupes de lignes de table.

Martin Smith
la source
12
En ce qui concerne la spécification HTML5, cela change légèrement, mais le fondamental "oui, plusieurs tbodyéléments sont très bien) reste. Plus précisément, vous êtes maintenant autorisé à mettre le seul tfootélément après le tbodysi vous le souhaitez . (Ils ont soigneusement décalé l'aspect DTD en disant qu'ils n'en fournissent pas .) :-)
TJ Crowder
5
Merci pour cette réponse. Le référencement des spécifications est la réponse n ° 1 dans mon livre.
KernelCurry
1
Il attend donc un ou plusieurs. C'est faux, cela peut être un ensemble de <tr>donc ça pourrait aussi être zéro (c'est-à-dire un tbody ou un tr signifie que ça pourrait être juste un tr et pas de tbody.)
Alexis Wilke
@AlexisWilke cela est vrai selon les spécifications: la balise de début TBODY est toujours requise, sauf lorsque la table ne contient qu'un seul corps de table et aucune section de tête ou de pied de table
Gecko IT
14

Le problème de Martin Joiner est dû à une mauvaise compréhension de la <caption>balise.

La <caption>balise définit une légende de table.

La <caption>balise doit être le premier enfant de la <table>balise.

Vous ne pouvez spécifier qu'une seule légende par table.

Notez également que l' scopeattribut doit être placé sur un <th>élément et non sur un <tr>élément.

La bonne façon d'écrire une table multi-en-tête multi-corps serait quelque chose comme ceci:

<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
la source
La captionbalise doit suivre la tablebalise d' ouverture . developer.mozilla.org/en-US/docs/Web/HTML/Element/table
Cypher
Tu as raison. J'ai mal interprété les documents. J'ai corrigé l'erreur.
John Slegers
Spec recommande d'utiliser scope="rowgroup"(au lieu de col) pour les en- tbodytêtes. Voir l' exemple .
CletusW
7

Oui. Je les utilise pour masquer / révéler dynamiquement la partie pertinente d'une table, par exemple un cours. 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>

Un bouton peut être fourni pour basculer entre tout ou simplement le jour en cours en manipulant les corps sans traiter plusieurs lignes individuellement.

CPslashM
la source
4

EDIT: la captionbalise appartient à la table et ne doit donc exister qu'une seule fois. N'associez pas un captionà chaque tbodyélément comme je l'ai fait:

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

MAUVAIS EXEMPLE CI-DESSUS: NE PAS COPIER

L'exemple ci-dessus ne s'affiche pas comme prévu car l'écriture comme celle-ci indique une mauvaise compréhension de la captionbalise. Vous auriez besoin de beaucoup de hacks CSS pour le rendre correctement car vous iriez à l'encontre des normes.

J'ai cherché les normes W3C sur la captionbalise mais je n'ai pas pu trouver de règle explicite qui stipule qu'il ne doit y avoir qu'un seul captionélément par table mais c'est en fait le cas.

Martin Joiner
la source
3

De plus, si vous exécutez un document HTML avec plusieurs <tbody>balises via le validateur HTML du W3C , avec un DOCTYPE HTML5, il sera validé avec succès.

Berne
la source
2

J'ai créé un JSFiddle où j'ai deux ng-répétitions imbriquées avec des tables et le parent ng-repeat sur tbody. Si vous inspectez une ligne du tableau, vous verrez qu'il y a six éléments tbody, c'est-à-dire le niveau parent.

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>

(Note latérale: cela remplit le DOM si vous avez beaucoup de données aux deux niveaux, donc je travaille donc sur une directive pour récupérer les données et les remplacer, c'est-à-dire ajouter dans DOM lorsque vous cliquez sur parent et supprimer lorsqu'un autre est cliqué ou même parent Pour obtenir le type de comportement que vous trouvez sur Prisjakt.nu , si vous faites défiler les ordinateurs répertoriés et cliquez sur la ligne (pas les liens). Si vous faites cela et inspectez les éléments, vous verrez qu'un tr est ajouté et puis supprimé si le parent est cliqué à nouveau ou un autre.)

Pixique
la source