¿Podemos tener múltiples <tbody> en la misma <table>?

594

¿Podemos tener varias <tbody>etiquetas en el mismo <table>? En caso afirmativo, ¿en qué escenarios debemos usar varias <tbody>etiquetas?

Jitendra Vyas
fuente

Respuestas:

710

Sí, puede usarlos, por ejemplo, los uso para diseñar más fácilmente grupos de datos, como este:

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>

Puedes ver un ejemplo aquí . Solo funcionará en navegadores más nuevos, pero eso es lo que estoy admitiendo en mi aplicación actual, puede usar la agrupación para JavaScript, etc. Lo principal es que es una forma conveniente de agrupar visualmente las filas para que los datos sean mucho más legibles . Hay otros usos, por supuesto, pero en cuanto a los ejemplos aplicables, este es el más común para mí.

Nick Craver
fuente
66
ok gracias por una gran respuesta ¿Es importante para el lector de pantalla, uno tbodyo múltiples?
Jitendra Vyas
1
@ metal-gear-solid: en mi experiencia, los manejan bien, por ejemplo: como si fueran uno <tbody>. Cuando comienzas a anidar tablas, eso es lo que generalmente da problemas de navegación reales para un lector de pantalla.
Nick Craver
10
@metal: no, hay una diferencia semántica: varios <tbody>elementos describen grupos separados en la tabla, como se explicó en la respuesta. También debo añadir que es generalmente mejor a las células diana para los fondos, por lo que la CSS debe ser, por ejemplo,tbody:nth-child(odd) td { background: #f5f5f5; }
DisgruntledGoat
44
¿Cuál es la definición de "navegadores más nuevos"?
Tim Down
8
@TimDown: cuando dije "navegadores más nuevos" solo se refería al :nth-child()uso de CSS para la demostración vinculada, los múltiples <tbody>funcionarán en cualquier navegador.
Nick Craver
298

Si. De la DTD

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

Entonces espera uno o más. Luego continúa diciendo

Use múltiples secciones tbody cuando se necesiten reglas entre grupos de filas de tabla.

Martin Smith
fuente
12
A partir de la especificación HTML5, esto cambia levemente, pero el "sí, varios tbodyelementos están bien" sigue siendo fundamental . Específicamente, ahora se le permite colocar el tfootelemento después del tbodysi lo desea (desviaron cuidadosamente el aspecto DTD). diciendo que no proporcionan uno .) :-)
TJ Crowder
55
Gracias por esta respuesta Hacer referencia a las especificaciones es la respuesta n. ° 1 en mi libro.
KernelCurry
1
Entonces espera uno o más. Esto está mal, puede ser un conjunto de, <tr>por lo que también podría ser cero (es decir, un cuerpo o un tr significa que podría ser un tr y ningún cuerpo).
Alexis Wilke
@AlexisWilke esto es cierto de acuerdo con las especificaciones: la etiqueta de inicio TBODY siempre se requiere, excepto cuando la tabla contiene solo un cuerpo de tabla y no tiene secciones de cabeza o pie de mesa
Gecko IT
14

El problema de Martin Joiner es causado por un malentendido de la <caption>etiqueta.

La <caption>etiqueta define un título de tabla.

La <caption>etiqueta debe ser el primer hijo de la <table>etiqueta.

Puede especificar solo un título por tabla.

Además, tenga en cuenta que el scopeatributo debe colocarse en un <th>elemento y no en un <tr>elemento.

La forma correcta de escribir una tabla multi-encabezado multi-tbody sería algo como esto:

<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
fuente
La captionetiqueta debe seguir a la tableetiqueta de apertura . developer.mozilla.org/en-US/docs/Web/HTML/Element/table
Cypher
Tienes razón. De alguna manera malinterpreté los documentos. Arreglé el error.
John Slegers
Spec recomienda usar scope="rowgroup"(en lugar de col) para los tbodyencabezados. Ver ejemplo .
CletusW
7

Si. Los uso para ocultar / revelar dinámicamente la parte relevante de una tabla, por ejemplo, un curso. Verbigracia.

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

Se puede proporcionar un botón para alternar entre todo o solo el día actual manipulando los cuerpos sin procesar muchas filas individualmente.

CPslashM
fuente
4

EDITAR: la captionetiqueta pertenece a la tabla y, por lo tanto, solo debe existir una vez. No asocie un captiona cada tbodyelemento como lo hice yo:

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

MALO EJEMPLO ANTERIOR: NO COPIE

El ejemplo anterior no se procesa como cabría esperar porque escribir así indica un malentendido de la captionetiqueta. Necesitaría muchos hacks CSS para que se renderice correctamente porque iría en contra de los estándares.

Busqué los estándares W3Cs en la captionetiqueta, pero no pude encontrar una regla explícita que indique que debe haber solo un captionelemento por tabla, pero ese es el caso.

Martin Joiner
fuente
3

Además, si ejecuta un documento HTML con varias <tbody>etiquetas a través del Validador HTML del W3C , con un DOCTYPE HTML5, se validará con éxito.

Berna
fuente
2

He creado un JSFiddle donde tengo dos ng-repite anidadas con tablas, y el padre ng-repeat en tbody. Si inspecciona cualquier fila de la tabla, verá que hay seis elementos tbody, es decir, el nivel principal.

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>

(Nota al margen: esto llena el DOM si tiene una gran cantidad de datos en ambos niveles, por lo tanto, estoy trabajando en una directiva para recuperar datos y reemplazarlos, es decir, agregarlos al DOM cuando se hace clic en padre y eliminar cuando se hace clic en otro o en el mismo padre de nuevo. Para obtener el tipo de comportamiento que encuentra en Prisjakt.nu , si se desplaza hacia abajo a las computadoras enumeradas y hace clic en la fila (no en los enlaces). Si lo hace e inspecciona los elementos, verá que se agrega un tr y luego se elimina si se hace clic en padre nuevamente u otro.)

Pixic
fuente