En el Mòdul 3 vam tancar el recorregut pels quatre principis POUR entesos com a requisits: vam aprendre què exigeix WCAG a cada criteri. Ara comença la part d'implementació: com es compleix amb HTML i CSS reals. I arrenquem per on cal arrencar, perquè és la via més directa, barata i robusta d'aconseguir accessibilitat: l'HTML semàntic. Quan tries l'element correcte, el navegador et regala name, role i value (els tres pilars del criteri 4.1.2 que vam veure com a requisit) sense que escriguis ni una línia de JavaScript ni d'ARIA. Un <button> ja "és" un botó per al lector de pantalla de la Marta; un <nav> ja "és" una regió de navegació per la qual la Lucía pot saltar. La semàntica és, literalment, accessibilitat gratis.

En aquesta lliçó construïm l'esquelet de la landing i el catàleg de Cursalia utilitzant els elements adequats i veurem, contrastant marcatge bo davant de dolent, per què l'etiqueta que tries canvia per complet l'experiència de les tecnologies d'assistència.

Contingut

  1. Per què la semàntica dona name/role/value gratis
  2. Landmarks: les regions de la pàgina
  3. Jerarquia d'encapçalaments h1–h6
  4. Llistes: ul, ol i dl
  5. Taules de dades accessibles
  6. Botó vs enllaç: l'error del <div onclick>
  7. Controls de formulari natius (menció)
  8. Atributs de pàgina: lang, title i el skip link
  9. La landing de Cursalia: bona vs mala estructura
  10. Errors comuns i consells
  11. Exercicis
  12. Conclusió

Per què la semàntica dona name/role/value gratis

Recordem del Mòdul 2 l'arbre d'accessibilitat: el navegador construeix, a partir del teu HTML, una versió paral·lela del DOM que exposa a les tecnologies d'assistència el rol (què és l'element), el nom (com es diu) i el valor/estat (en quina situació està) de cada component. L'HTML semàntic és la manera com "omples" aquest arbre sense esforç.

Si escrius... L'arbre d'accessibilitat exposa... Cost extra
<button>Matricula't</button> role=button, name="Matricula't", focusable, activable amb Enter/Espai Zero
<nav> role=navigation (landmark saltable) Zero
<h2>Cursos destacats</h2> role=heading, level=2 (apareix a la llista d'encapçalaments) Zero
<div class="button" onclick> role=generic (res!), no focusable, no activable amb teclat Molt: cal recrear-ho tot amb ARIA + JS

La conclusió pràctica és la regla d'or de l'accessibilitat, que repetirem a 04-03:

Utilitza l'element HTML natiu que ja té la semàntica que necessites abans de recrear-la amb ARIA i JavaScript.

Landmarks: les regions de la pàgina

Els landmarks (regions de referència) són regions d'alt nivell que permeten a un usuari de lector de pantalla com la Marta saltar directament a "el contingut principal" o "la navegació" sense escoltar tota la pàgina. NVDA ofereix una tecla per llistar landmarks igual que n'ofereix una per llistar encapçalaments.

Els elements de secció d'HTML es mapegen automàticament a rols landmark:

Element HTML Rol d'accessibilitat (landmark) Ús
<header> (a nivell de pàgina) banner Capçalera del lloc: logo, cercador
<nav> navigation Menús de navegació
<main> main Contingut principal (un per pàgina)
<aside> complementary Contingut relacionat: filtres, promos
<footer> (a nivell de pàgina) contentinfo Peu: avisos legals, contacte
<section> amb nom region Secció temàtica amb encapçalament
<article> article Contingut autònom (una targeta de curs)

Exemple correcte de l'estructura d'una pàgina de Cursalia:

<body>
  <header>
    <a href="/"><img src="logo-cursalia.svg" alt="Cursalia"></a>
    <nav aria-label="Principal">
      <ul>
        <li><a href="/cursos">Catàleg</a></li>
        <li><a href="/precios">Preus</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <h1>Aprèn al teu ritme amb Cursalia</h1>
    <!-- contingut principal -->
  </main>

  <aside aria-label="Filtres del catàleg">
    <!-- filtres -->
  </aside>

  <footer>
    <p>© 2026 Cursalia</p>
  </footer>
</body>

Davant de la mateixa estructura feta només amb <div>, que no aporta cap regió:

<!-- INCORRECTE: per al lector de pantalla això és una sopa de "grups genèrics" -->
<div class="header">...</div>
<div class="nav">...</div>
<div class="content">...</div>
<div class="footer">...</div>

Per al lector de la Marta, la primera versió té cinc regions anomenades per les quals navegar; la segona no en té cap. Fixa't en el detall d'aria-label="Principal" al <nav>: si hi ha més d'un landmark del mateix tipus (per exemple, la navegació principal i una altra al peu), cal distingir-los amb un nom. Això és semàntica reforçada, no reemplaçada; ho veurem bé a 04-03.

graph TD
    A[body] --> B["header → banner"]
    A --> C["nav → navigation"]
    A --> D["main → main"]
    A --> E["aside → complementary"]
    A --> F["footer → contentinfo"]
    D --> G["article → article (targeta de curs)"]

Jerarquia d'encapçalaments h1–h6

Els encapçalaments no són "text gran": són l'índex navegable de la pàgina. La Marta prem la tecla H a NVDA per saltar d'encapçalament en encapçalament i fer-se un mapa mental del contingut, i pot prémer 2 per anar només als de nivell 2. Per això la jerarquia ha de reflectir l'estructura lògica, no la mida visual (la mida és cosa del CSS).

Regles del criteri 1.3.1 aplicades a encapçalaments:

  • Un sol <h1> per pàgina, que descriu el tema global.
  • No saltar nivells en baixar: després d'un <h2> no es passa directament a un <h4>.
  • El nivell indica jerarquia, no aparença. Si vols un h2 petit, l'empetiteixes amb CSS.
<!-- CORRECTE: jerarquia sense salts -->
<main>
  <h1>Catàleg de cursos</h1>
    <h2>Cursos destacats</h2>
      <h3>Accessibilitat Web</h3>
      <h3>JavaScript modern</h3>
    <h2>Novetats</h2>
      <h3>Disseny de sistemes</h3>
</main>
<!-- INCORRECTE: es tria l'encapçalament per la seva mida, no per jerarquia -->
<h1>Catàleg de cursos</h1>
<h4>Cursos destacats</h4>   <!-- salta d'1 a 4 -->
<h2>Accessibilitat Web</h2>   <!-- i ara puja a 2: l'índex queda incoherent -->

Llistes: ul, ol i dl

Quan marques un conjunt d'elements com a llista, el lector de pantalla anuncia "llista de 8 elements" i permet navegar-hi. Aquest context es perd si utilitzes <div> o <br>. Tres tipus:

  • <ul>: llista no ordenada (l'ordre no importa). El menú de navegació, les targetes del catàleg.
  • <ol>: llista ordenada (la seqüència importa). Els passos de matriculació.
  • <dl>: llista de definicions (parells terme/descripció). La fitxa d'un curs: "Durada: 20 h", "Nivell: Intermedi".
<!-- CORRECTE: la graella de cursos ÉS una llista -->
<ul class="grid-cursos">
  <li><article>...targeta Accessibilitat Web...</article></li>
  <li><article>...targeta JavaScript modern...</article></li>
</ul>

<!-- CORRECTE: metadades del curs com a llista de definicions -->
<dl>
  <dt>Durada</dt><dd>20 hores</dd>
  <dt>Nivell</dt><dd>Intermedi</dd>
  <dt>Idioma</dt><dd>Català</dd>
</dl>
<!-- INCORRECTE: sembla una llista, però no ho és per a ningú més que per a l'ull -->
<div class="grid-cursos">
  <div>...targeta...</div>
  <div>...targeta...</div>
</div>

Taules de dades accessibles

Una taula de dades (no de maquetació, que no s'ha d'utilitzar) necessita marcatge semàntic perquè la Marta entengui a quina fila i columna pertany cada cel·la. Les peces clau:

  • <caption>: títol de la taula, el primer que anuncia el lector.
  • <th> per a les cel·les d'encapçalament, davant de <td> per a dades.
  • scope="col" / scope="row": indica si l'encapçalament governa una columna o una fila.
  • <thead> / <tbody>: separen encapçalaments del cos.
<!-- CORRECTE: comparativa de plans de Cursalia -->
<table>
  <caption>Comparativa de plans de subscripció</caption>
  <thead>
    <tr>
      <th scope="col">Pla</th>
      <th scope="col">Preu/mes</th>
      <th scope="col">Cursos inclosos</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Bàsic</th>
      <td>9 €</td>
      <td>50</td>
    </tr>
    <tr>
      <th scope="row">Pro</th>
      <td>19 €</td>
      <td>Tots</td>
    </tr>
  </tbody>
</table>

Sense scope ni <th>, el lector recita una lletania de números sense dir "Pro, Preu/mes, 19 €": la relació entre dada i encapçalament es perd.

Botó vs enllaç: l'error del <div onclick>

És una de les decisions més equivocades a la pràctica. La regla és senzilla:

  • <a href> (enllaç): navega a un altre lloc (una altra pàgina, una altra secció, una àncora). Rol link. El lector l'anuncia com a "enllaç".
  • <button>: executa una acció a la pàgina actual (obrir el filtre, enviar el formulari, reproduir el vídeo). Rol button. El lector l'anuncia com a "botó".

Tots dos són focusables i operables amb teclat de fàbrica: l'enllaç s'activa amb Enter, el botó amb Enter i Espai. Un <div> o un <span> amb onclick no té cap d'aquestes propietats.

<!-- CORRECTE -->
<a href="/cursos/accesibilidad-web">Veure curs d'Accessibilitat Web</a>
<button type="button">Obre filtres</button>
<!-- INCORRECTE: la trampa clàssica -->
<div class="btn" onclick="obreFiltres()">Obre filtres</div>

Aquest <div> falla en cascada per a la Lucía (que només fa servir teclat) i la Marta:

  1. No rep focus: la Lucía no pot tabular fins a ell (caldria forçar tabindex="0").
  2. No s'activa amb teclat: encara que tingués focus, Enter/Espai no fan res (caldria escoltar tecles amb JS).
  3. No té rol: la Marta no sent "botó", sent text solt, i no sap que és premible.

Per "arreglar" aquest <div> cal afegir role="button", tabindex="0", gestors de teclat per a Enter i Espai... és a dir, reimplementar a mà tot el que <button> et dona gratis. Recrear controls natius amb ARIA és precisament el que veurem al Mòdul 5; aquí la lliçó és evitar haver de fer-ho.

Controls de formulari natius (menció)

Els elements <input>, <select>, <textarea> i <button> porten de sèrie rol, focus, operació per teclat i estats. Un <input type="checkbox"> ja comunica marcat/desmarcat; un <select> ja és una llista desplegable operable. Aprofitar-los és la base d'un formulari accessible, però la seva associació amb etiquetes, l'agrupació i els errors són el tema complet de la lliçó 04-02, així que aquí només deixem constància que existeixen i que són la primera opció.

Atributs de pàgina: lang, title i el skip link

Tres detalls del document amb gran impacte:

  • lang a <html>: li diu al lector quin idioma pronunciar. Sense ell, NVDA podria llegir el català de Cursalia amb fonètica anglesa i tornar-se inintel·ligible. Si a dins hi ha un fragment en un altre idioma, es marca amb lang en aquell element (això connecta amb la i18n del Mòdul 7).
  • <title> de la pàgina: és el primer que anuncia el lector en carregar i el que es veu a la pestanya. Ha de ser únic i descriptiu: Catàleg de cursos · Cursalia.
  • Skip link ("salta al contingut"): un enllaç que és el primer focus de la pàgina i porta directament al <main>, perquè la Lucía no hagi de tabular per tota la capçalera i el menú a cada pàgina.
<!doctype html>
<html lang="ca">
<head>
  <title>Catàleg de cursos · Cursalia</title>
</head>
<body>
  <!-- Primer element focusable de la pàgina -->
  <a class="skip-link" href="#contenido">Salta al contingut principal</a>
  <header>...</header>
  <main id="contenido" tabindex="-1">
    <h1>Catàleg de cursos</h1>
  </main>
</body>
</html>

El skip link se sol amagar visualment i mostrar-se només en rebre focus, per no molestar l'usuari de ratolí però continuar estant disponible per al teclat:

.skip-link {
  position: absolute;
  left: -9999px;      /* fora de pantalla, però present al DOM */
}
.skip-link:focus {
  left: 1rem;
  top: 1rem;          /* apareix en tabular cap a ell */
}

La landing de Cursalia: bona vs mala estructura

Ajuntem-ho tot comparant dues versions de la mateixa landing.

<!-- INCORRECTE: tot divs, sense encapçalaments reals, "botons" que són divs -->
<div class="top">
  <div class="menu"><span onclick="ves('/cursos')">Catàleg</span></div>
</div>
<div class="hero">
  <div class="big">Aprèn al teu ritme</div>
  <div class="btn" onclick="registre()">Comença gratis</div>
</div>
<div class="cards">
  <div class="card">Accessibilitat Web</div>
  <div class="card">JavaScript modern</div>
</div>

Per a la Marta això és una pàgina sense regions, sense encapçalaments i sense controls: impossible de recórrer amb eficiència. Per a la Lucía, res rep focus.

<!-- CORRECTE: mateix disseny visual, semàntica completa -->
<a class="skip-link" href="#contenido">Salta al contingut</a>
<header>
  <nav aria-label="Principal">
    <ul><li><a href="/cursos">Catàleg</a></li></ul>
  </nav>
</header>
<main id="contenido">
  <h1>Aprèn al teu ritme amb Cursalia</h1>
  <p><a class="cta" href="/registro">Comença gratis</a></p>

  <section aria-labelledby="destacados">
    <h2 id="destacados">Cursos destacats</h2>
    <ul class="cards">
      <li>
        <article>
          <h3><a href="/cursos/accesibilidad-web">Accessibilitat Web</a></h3>
          <img src="acc.webp" alt="">   <!-- alt a 05-04 -->
        </article>
      </li>
      <li>
        <article>
          <h3><a href="/cursos/javascript">JavaScript modern</a></h3>
        </article>
      </li>
    </ul>
  </section>
</main>

El CSS pot fer que totes dues es vegin idèntiques. La diferència no és als píxels, sinó en la informació estructural que una exposa i l'altra destrueix. (L'alt="" de la imatge té sentit i l'estudiarem a fons a 05-04.)

Errors Comuns i Consells

  • Utilitzar <div>/<span> per a tot. És l'error arrel. Abans d'escriure un <div>, pregunta't si existeix un element que signifiqui el que vols dir.
  • Triar l'encapçalament per la seva mida. Un <h3> no és "un títol mitjà"; és un nivell jeràrquic. Ajusta la mida amb CSS, mai canviant el nivell.
  • Diversos <h1> o salts de nivell. Trenquen l'índex de la pàgina. Un <h1>, i baixa d'un en un.
  • Botó que navega o enllaç que actua. Si canvia d'URL, és <a>; si actua a la pàgina, és <button>. No els intercanviïs per estètica.
  • Taules per maquetar. Reserva <table> per a dades tabulars; utilitza CSS Grid/Flexbox per a la disposició visual.
  • Oblidar lang i <title>. Són una línia cadascun i milloren dràsticament la lectura per veu.
  • Consell: navega la teva pròpia pàgina només amb el teclat (Tab, Enter) i amb la llista d'encapçalaments d'un lector. Si no pots recórrer-la, la teva semàntica està incompleta.

Exercicis

Exercici 1: convertir una div-soup en landmarks

Tens aquest fragment de la capçalera de Cursalia. Reescriu-lo amb els elements semàntics correctes, afegint el nom necessari al nav.

<div class="header">
  <div class="logo">Cursalia</div>
  <div class="menu">
    <div class="item"><span onclick="ves('/cursos')">Catàleg</span></div>
    <div class="item"><span onclick="ves('/precios')">Preus</span></div>
  </div>
</div>

Exercici 2: arreglar la jerarquia d'encapçalaments

Un maquetador va triar els encapçalaments per la seva mida visual. Corregeix els nivells perquè la jerarquia sigui lògica i sense salts.

<h1>Fitxa del curs: Accessibilitat Web</h1>
<h3>Descripció</h3>
<h2>Temari</h2>
<h4>Mòdul 4: HTML i CSS</h4>

Exercici 3: botó o enllaç

Per a cada control, decideix si ha de ser <a href> o <button> i escriu-lo:

  1. "Anar a la pàgina de preus".
  2. "Reproduir la vídeo-lliçó" (a la mateixa pàgina).
  3. "Descarregar el certificat" (navega a un PDF).
  4. "Obrir el desplegable de filtres del catàleg".

Solucions

Solució 1. Cada <div> estructural se substitueix pel seu equivalent semàntic; els "items" premibles que naveguen són enllaços reals:

<header>
  <a href="/" class="logo">Cursalia</a>
  <nav aria-label="Principal">
    <ul>
      <li><a href="/cursos">Catàleg</a></li>
      <li><a href="/precios">Preus</a></li>
    </ul>
  </nav>
</header>

L'aria-label="Principal" és necessari perquè probablement hi hagi un altre <nav> (per exemple al peu) i cal distingir-los.

Solució 2. Ha de baixar de forma progressiva sense salts i amb un sol <h1>:

<h1>Fitxa del curs: Accessibilitat Web</h1>
<h2>Descripció</h2>
<h2>Temari</h2>
<h3>Mòdul 4: HTML i CSS</h3>

"Descripció" i "Temari" són seccions germanes de primer nivell (h2); el mòdul penja del temari (h3).

Solució 3.

  1. Enllaç: navega a una altra pàgina → <a href="/precios">Anar a preus</a>.
  2. Botó: acciona alguna cosa a la mateixa pàgina → <button type="button">Reprodueix</button>.
  3. Enllaç: porta a un recurs (el PDF) → <a href="/certificado.pdf" download>Descarrega certificat</a>.
  4. Botó: obre/tanca un panell a la pàgina → <button type="button" aria-expanded="false">Filtres</button>. L'aria-expanded i el seu comportament els veurem a 04-03 i 05-01.

Conclusió

L'HTML semàntic és el fonament de tota la resta en accessibilitat: triant bé els elements obtens name, role i value gratis, regions navegables, un índex d'encapçalaments i controls operables amb teclat, sense escriure codi addicional. Hem maquetat la landing de Cursalia amb landmarks, jerarquia d'encapçalaments, llistes, taules de dades, enllaços i botons correctes, i hem fixat la regla d'or: utilitza l'element natiu abans que recrear-lo amb ARIA (idea que ampliarem a 04-03).

El següent pas natural és el punt on la semàntica es torna més delicada i on es concentren els criteris 3.3.x: els formularis. A la lliçó 04-02 · Formularis Accessibles aplicarem tot això al formulari de matrícula de Cursalia —etiquetes, agrupacions, camps obligatoris, ajudes i missatges d'error— perquè la Marta, l'Hugo i la Lucía puguin completar-lo sense barreres.

© Copyright 2026. Tots els drets reservats