Apuntes sobre Html2

Cuando uno enseña, dos aprenden.

Tablas

Estructura básica

Una tabla HTML organiza datos en filas y columnas. Se construye con tres etiquetas fundamentales: <table> envuelve la tabla entera, <tr> (table row) define cada fila, y <td> (table data) define cada celda dentro de una fila:

<table>
    <tr>
        <td>Lunes</td>
        <td>9:00</td>
        <td>Matemáticas</td>
    </tr>
    <tr>
        <td>Lunes</td>
        <td>11:00</td>
        <td>Historia</td>
    </tr>
</table>

Las columnas no se declaran explícitamente: se forman solas según el número de celdas de cada fila. Si una fila tiene más celdas que otra, la tabla se desajusta, así que todas las filas deben tener el mismo número de celdas (salvo cuando se usa colspan o rowspan, que veremos más adelante).

Por defecto, las tablas no tienen bordes visibles. La apariencia habitual de tabla de datos (con líneas separando filas y columnas) requiere CSS.

Cabeceras y título

<th> (table header) marca una celda como cabecera. El navegador la muestra en negrita y centrada por defecto, pero lo importante es su significado semántico: indica que esa celda describe el contenido de su columna o fila:

<table>
    <tr>
        <th>Día</th>
        <th>Hora</th>
        <th>Asignatura</th>
    </tr>
    <tr>
        <td>Lunes</td>
        <td>9:00</td>
        <td>Matemáticas</td>
    </tr>
</table>

El atributo scope en <th> especifica si la cabecera corresponde a una columna (scope="col") o a una fila (scope="row"). Es importante para la accesibilidad: los lectores de pantalla lo usan para relacionar cada celda con su cabecera correspondiente.

<tr>
    <th scope="col">Día</th>
    <th scope="col">Hora</th>
    <th scope="col">Asignatura</th>
</tr>

<caption> añade un título a la tabla. Debe ser el primer hijo de <table> y aparece centrado encima por defecto. Su posición se controla con CSS:

<table>
    <caption>Horario semanal — primer trimestre</caption>
    <tr>
        <th scope="col">Día</th>
        <th scope="col">Hora</th>
        <th scope="col">Asignatura</th>
    </tr>
    ...
</table>
caption {
    caption-side: bottom; /* top es el valor por defecto */
    text-align: left;
    font-size: 0.875rem;
    color: #666;
}

Estructura semántica

Para tablas de más de unas pocas filas, HTML ofrece tres elementos que dividen la tabla en secciones con significado propio:

<thead> agrupa las filas de cabecera. <tbody> agrupa el cuerpo de datos. <tfoot> agrupa las filas de pie (totales, notas, resúmenes):

<table>
    <caption>Resultados del equipo</caption>
    <thead>
        <tr>
            <th scope="col">Jugador</th>
            <th scope="col">Goles</th>
            <th scope="col">Asistencias</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>García</td>
            <td>12</td>
            <td>5</td>
        </tr>
        <tr>
            <td>López</td>
            <td>8</td>
            <td>11</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th scope="row">Total</th>
            <td>20</td>
            <td>16</td>
        </tr>
    </tfoot>
</table>

Estas secciones tienen utilidad práctica además de semántica. En tablas largas, el navegador puede mantener <thead> y <tfoot> visibles al imprimir mientras el cuerpo se pagina. Con CSS también permiten aplicar estilos diferenciados a cada sección de forma sencilla.

Fusión de celdas

colspan hace que una celda ocupe varias columnas. rowspan hace que ocupe varias filas. Los dos atributos reciben un número entero:

<table>
    <tr>
        <th scope="col" colspan="2">Contacto</th>
        <th scope="col">Departamento</th>
    </tr>
    <tr>
        <td>Ana Martín</td>
        <td>ana@empresa.com</td>
        <td rowspan="2">Diseño</td>
    </tr>
    <tr>
        <td>Carlos Ruiz</td>
        <td>carlos@empresa.com</td>
        <!-- No hay tercera celda: rowspan la ocupa -->
    </tr>
</table>

La regla a recordar con rowspan: cuando una celda ocupa dos filas, la fila siguiente tiene una celda menos. Si el número total de celdas no cuadra, la tabla se desajusta visualmente y es difícil de depurar. Conviene dibujar la estructura en papel antes de escribir el HTML cuando hay varias fusiones.

Ver ejemplo: colspan y rowspan

Columnas: <col> y <colgroup>

Aplicar estilos a una columna entera normalmente requeriría añadir una clase a cada celda de esa columna. <colgroup> y <col> permiten hacerlo de forma más limpia desde el HTML:

<table>
    <colgroup>
        <col style="width: 40%">
        <col style="width: 20%">
        <col style="width: 40%">
    </colgroup>
    <tr>
        <td>Nombre</td>
        <td>Edad</td>
        <td>Ciudad</td>
    </tr>
</table>

<colgroup> debe colocarse justo después de <caption> (si lo hay) y antes de <thead>. Cada <col> corresponde a una columna en el orden en que aparecen. Si varias columnas comparten el mismo estilo, el atributo span evita repetir:

<colgroup>
    <col>                      <!-- primera columna: sin estilo especial -->
    <col span="2" style="background-color: #f0f7e6"> <!-- columnas 2 y 3 -->
</colgroup>

Nota: <col> acepta un subconjunto limitado de propiedades CSS: básicamente width, background, border y visibility. Para el resto de estilos, sigue siendo necesario aplicarlos a las celdas directamente.

CSS: bordes

Por defecto, <table>, <td> y <th> son elementos independientes y cada uno puede tener su propio borde. El resultado por defecto es un doble borde entre celdas. La propiedad border-collapse controla este comportamiento:

table {
    border-collapse: collapse; /* los bordes adyacentes se fusionan en uno solo */
}

table {
    border-collapse: separate; /* cada celda mantiene su propio borde (valor por defecto) */
}

Con border-collapse: collapse, el borde entre dos celdas contiguas se convierte en uno solo. Es el comportamiento esperado para la mayoría de tablas de datos.

Con border-collapse: separate, se puede usar border-spacing para añadir espacio entre celdas:

table {
    border-collapse: separate;
    border-spacing: 4px 8px; /* horizontal vertical */
}

Una tabla típica con bordes se escribe así:

table {
    border-collapse: collapse;
    width: 100%;
}

th, td {
    border: 1px solid #ddd;
    padding: 0.6em 1em;
    text-align: left;
}

th {
    background-color: #f5f5f5;
}

CSS: ancho y layout

Por defecto, el navegador calcula el ancho de cada columna según el contenido más largo de esa columna. Este modo se llama table-layout: auto y puede producir tablas con anchos de columna irregulares o impredecibles.

table-layout: fixed cambia el algoritmo: el ancho de cada columna lo determina la primera fila (o las reglas de <col>), no el contenido. Esto mejora el rendimiento en tablas grandes y da control preciso sobre las proporciones:

table {
    table-layout: fixed;
    width: 100%;
}

th:nth-child(1) { width: 40%; }
th:nth-child(2) { width: 30%; }
th:nth-child(3) { width: 30%; }

Con table-layout: fixed, si el contenido de una celda es más largo que su columna, se desborda. Para evitarlo, se suele combinar con overflow: hidden y text-overflow: ellipsis en las celdas.

CSS: filas alternas y hover

El efecto de filas alternas (zebra) mejora la legibilidad en tablas con muchas filas. Se consigue con :nth-child:

tbody tr:nth-child(odd) {
    background-color: #f9f9f9;
}

tbody tr:nth-child(even) {
    background-color: #ffffff;
}

El resaltado al pasar el ratón añade interactividad y ayuda a seguir una fila en tablas anchas:

tbody tr:hover {
    background-color: #eef4ff;
}

Cuando se usan filas alternas y hover a la vez, :hover debe declararse después de :nth-child para que lo sobreescriba correctamente en cascada.

Tablas responsivas

Las tablas con muchas columnas son difíciles de mostrar en pantallas pequeñas. La solución más sencilla es envolver la tabla en un contenedor con scroll horizontal:

.tabla-wrapper {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch; /* scroll suave en iOS */
}
<div class="tabla-wrapper">
    <table>
        ...
    </table>
</div>

La tabla mantiene su estructura completa y el usuario puede desplazarse horizontalmente para ver las columnas que no caben en pantalla. Es la técnica más robusta y compatible, aunque no la más elegante.

Accesibilidad

Una tabla bien estructurada es accesible por defecto si se usan correctamente las etiquetas semánticas. Los puntos más importantes:

Usa siempre <th> con scope para las cabeceras. Sin scope, los lectores de pantalla no pueden asociar cada celda de datos con su cabecera correspondiente, especialmente en tablas con cabeceras tanto en filas como en columnas.

Incluye <caption> en todas las tablas de datos. Proporciona un resumen del contenido antes de que el lector de pantalla entre en la tabla.

No uses tablas para maquetación. Las tablas tienen una semántica implícita de datos tabulares y los lectores de pantalla las anuncian como tales. Una tabla usada para maquetar la página resulta confusa e innavegable para usuarios de tecnología asistiva.

Material histórico

Los atributos HTML para controlar la presentación de tablas fueron declarados obsoletos en HTML5. El equivalente de cada uno es CSS:

Atributo HTML (obsoleto) Equivalente CSS
border="1" border: 1px solid en table, td y th
width="80%" width: 80%
align="center" margin: 0 auto (para centrar la tabla)
cellpadding="10" padding: 10px en td y th
cellspacing="5" border-spacing: 5px (requiere border-collapse: separate)
bgcolor="#ccc" background-color: #ccc
valign="top" vertical-align: top

Tu proyecto

Añade una tabla de proyectos completados a proyecto.html, con tres o cuatro filas de ejemplo. Estilízala en estilos.css con filas alternas y sin bordes recargados:

<h2 id="proyectos">Proyectos</h2>
<table class="tabla-proyectos">
  <thead>
    <tr>
      <th scope="col">Proyecto</th>
      <th scope="col">Tipo</th>
      <th scope="col">Año</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>Vivienda en el Retiro</td><td>Residencial</td><td>2023</td></tr>
    <tr><td>Estudio fotográfico Lumen</td><td>Comercial</td><td>2022</td></tr>
    <tr><td>Casa La Vera</td><td>Obra nueva</td><td>2021</td></tr>
  </tbody>
</table>
.tabla-proyectos {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.95rem;
}

.tabla-proyectos th,
.tabla-proyectos td {
    text-align: left;
    padding: 0.6rem 0.8rem;
    border-bottom: 1px solid #eee;
}

.tabla-proyectos th {
    color: #888;
    font-weight: 400;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.tabla-proyectos tr:hover td {
    background-color: #f5f5f3;
}

Recapitulación

  • Una tabla se construye con <table>, <tr> y <td>. Las columnas se forman automáticamente: todas las filas deben tener el mismo número de celdas.
  • <th> marca celdas de cabecera. El atributo scope="col" o scope="row" relaciona la cabecera con su columna o fila para los lectores de pantalla.
  • <caption> añade un título a la tabla. caption-side controla su posición.
  • <thead>, <tbody> y <tfoot> dividen la tabla en secciones semánticas.
  • colspan fusiona celdas en horizontal, rowspan en vertical. La fila siguiente tiene una celda menos por cada rowspan activo.
  • <colgroup> y <col> permiten aplicar estilos (ancho, fondo) a columnas enteras.
  • border-collapse: collapse fusiona los bordes entre celdas en uno solo. border-spacing solo funciona con border-collapse: separate.
  • table-layout: fixed da control preciso sobre el ancho de las columnas y mejora el rendimiento en tablas grandes.
  • :nth-child(odd/even) alterna el fondo de las filas. tr:hover resalta la fila bajo el cursor.
  • Para tablas con muchas columnas en móvil, envuelve la tabla en un contenedor con overflow-x: auto.
  • Los atributos border, cellpadding, cellspacing, align y bgcolor en tablas son obsoletos. Todo se hace con CSS.

En la próxima lección: formularios: cómo recoger datos del usuario con <input>, <select> y <textarea>.

TOP