Les taules HTML tenen mala fama. Sovint es consideren dolentes per a l’accessibilitat, mala pràctica i antiquades.
Aquesta fama només és justa quan fem servir les taules per a la maquetació. La majoria de llocs web moderns no ho fan, però la majoria de correus electrònics sí. Les taules tenen valor semàntic (significat) i comportament funcional. Les taules funcionen bé per a dades en files i columnes. No funcionen bé per a la maquetació.
Pots fer servir role="presentation" per eliminar el valor semàntic i el comportament funcional d’una taula. Tot i així, l’ordre del contingut al DOM ha de continuar tenint sentit.
Vegem un exemple d’una taula amb informació d’inventari d’una petita fleca:
| Inventari setmanal per categoria | ||||||
| Categoria | Article | Preus | Stock | Estat | ||
| Cost unitari | Preu de venda | En stock | Nivell de reposició | |||
| Pans | Baguette | $0.65 | $3.25 | 42 | 20 | OK |
| Pa de massa mare | $0.90 | $4.75 | 15 | 18 | Baix | |
| Pa de sègol | $0.85 | $4.50 | 27 | 15 | OK | |
| Brioixeria | Croissant de mantega | $0.55 | $2.95 | 60 | 25 | OK |
| Danesa de cireres | $0.70 | $3.50 | 8 | 12 | Baix | |
| Pastissos | Porció de pastís de pastanaga | $1.10 | $4.95 | 18 | 10 | OK |
| Porció de pastís de formatge | $1.25 | $5.25 | 22 | 10 | OK | |
| Totals | — | — | 192 unitats | 110 unitats | 2 articles baixos | |
No sembla malament, oi? El CSS fa que les parts siguin fàcils de distingir, i la maquetació té sentit.
Aquest és el problema principal. La informació important, com les relacions i l’estructura, depèn només dels estils visuals i la posició. Les persones que fan servir tecnologia d’assistència no poden accedir a aquesta informació.
Al final d’aquest article, trobaràs la mateixa taula amb tot el que li falta a la primera versió.
Anem pas a pas.
Cel·les d’encapçalament
Aquest és el canvi més fàcil de fer. Totes les cel·les de la primera taula fan servir l’etiqueta de cel·la de dades, <td>. Però l’HTML també té una etiqueta de cel·la d’encapçalament, <th>, per a les cel·les que actuen com a encapçalaments.
Fes servir l’atribut scope per marcar una cel·la d’encapçalament com a encapçalament de columna (scope="col") o encapçalament de fila (scope="row"). Això et dona encapçalaments a la part superior de cada columna, i un encapçalament a l’inici de cada fila.
Grups de files
Una taula pot tenir tant grups de columnes com grups de files. L’atribut scope també accepta els valors colgroup i rowgroup per a aquests casos.
Hi ha 3 grups de files principals: la capçalera de la taula (<thead>), el cos de la taula (<tbody>) i el peu de la taula (<tfoot>). Són especialment útils per a taules grans.
En el nostre exemple:
- Els encapçalaments superiors van a la capçalera de la taula.
- Les dades dels productes van al cos de la taula.
- Els totals van al peu de la taula.
Això facilita la navegació entre les parts principals.
Títol
Aquesta part importa. Un títol (caption) descriu el contingut de la taula perquè les persones puguin decidir si necessiten o volen llegir les dades.
Aquí tens diverses opcions. Pots fer servir:
- Un
<caption>(o<figcaption>si la taula està dins d’un<figure>) - Text, com un paràgraf, col·locat abans de la taula
- Text en un altre element, vinculat amb l’atribut
aria-describedby
Aquests mètodes funcionen igual de bé. Fes servir només un.
Un avantatge de <caption>: hi pots imbricar un element <details>, amb informació addicional en un desplegable <summary>, o afegir text que estigui ocult visualment però que els lectors de pantalla puguin continuar llegint. Vaig fer servir aquest segon enfocament en l’exemple al final de l’article. Dona a tothom una etiqueta curta i visible, i als usuaris de lectors de pantalla un text més llarg amb més context.
Nota: l’atribut summary a l’element <table> és obsolet a l’HTML Living Standard. No el facis servir.
Encapçalaments multinivell
Aquesta part marca la diferència més gran per a les persones que fan servir tecnologia d’assistència, especialment en taules complexes.
En el nostre exemple, tant les columnes com les files tenen diversos nivells d’encapçalament. Això pot semblar complicat, però la solució és senzilla.
Primer, afegeix un atribut id únic a cada cel·la d’encapçalament. Després afegeix un atribut headers a cada cel·la de dades. Enumera totes les cel·les d’encapçalament amb què es relaciona, tant de columna com de fila, a tots els nivells.
Per exemple, la cel·la amb el preu de venda de la baguette inclou: headers="row-breads row-baguette col-pricing col-retail". Això permet que els lectors de pantalla anunciïn tots els encapçalaments relacionats amb aquesta cel·la.
Conclusió
Les taules accessibles no són difícils de construir. El marcatge pot arribar a ser detallat, ja que estàs vinculant moltes cel·les amb molts encapçalaments. Però és senzill d’implementar. I converteix una experiència lenta i frustrant —desplaçar-se per dades interminables sense context— en una font d’informació clara i utilitzable.
| Categoria | Article | Preus | Stock | Estat | ||
|---|---|---|---|---|---|---|
| Cost unitari | Preu de venda | En stock | Nivell de reposició | |||
| Pans | Baguette | $0.65 | $3.25 | 42 | 20 | OK |
| Pa de massa mare | $0.90 | $4.75 | 15 | 18 | Baix | |
| Pa de sègol | $0.85 | $4.50 | 27 | 15 | OK | |
| Brioixeria | Croissant de mantega | $0.55 | $2.95 | 60 | 25 | OK |
| Danesa de cireres | $0.70 | $3.50 | 8 | 12 | Baix | |
| Pastissos | Porció de pastís de pastanaga | $1.10 | $4.95 | 18 | 10 | OK |
| Porció de pastís de formatge | $1.25 | $5.25 | 22 | 10 | OK | |
| Totals | — | — | 192 unitats | 110 unitats | 2 articles baixos | |