EN 301 549 · EAA · WCAG 2.1
Informe de accesibilidad web
Resultados claros. Próximos pasos accionables.
Análisis automatizado de barreras de accesibilidad en la página pública de la tienda.
Accy · Cumplimiento de accesibilidad para tiendas online europeas.
Analizado el 15 de septiembre de 2026 a las 20:55
tienda-de-ejemplo.es
Riesgo crítico
- 22 reglas incumplidas
- 9 reglas superadas
- 5 para revisar a mano
29 incidencias en total, repartidas así
- 6 Crítico
- 15 Grave
- 7 Moderado
- 1 Leve
- Plataforma detectada
- Shopify · Dawn
- No hemos encontrado declaración de accesibilidad
- Generar una gratis →
- Alcance técnico
- Una página pública, analizada sobre el HTML y el CSS que entrega el servidor.
Lectura recomendada
Empieza por las 21 incidencias críticas y graves de la sección 02: son las que impiden comprar. Después valida a mano los 5 puntos que ninguna herramienta puede confirmar, recorriendo ficha de producto, carrito y pago con teclado y lector de pantalla. Y vuelve a analizar la tienda al terminar: este informe lleva fecha y sirve como control de regresión.
| Hallazgo | Riesgo | Referencia |
|---|---|---|
| Enlaces sin nombreHay enlaces sin texto visible ni nombre accesible. | Crítico | WCAG 2.4.4, 4.1.2 (A) · EN 301 549 9.2.4.4, 9.4.1.2 |
| Campos de formulario sin etiquetaHay campos de formulario sin nombre accesible: ni <label>, ni aria-label, ni aria-labelledby. | Crítico | WCAG 1.3.1, 3.3.2, 4.1.2 (A) · EN 301 549 9.1.3.1, 9.3.3.2, 9.4.1.2 |
| Botones sin nombreHay botones sin texto visible ni nombre accesible. | Crítico | WCAG 4.1.2 (A) · EN 301 549 9.4.1.2 |
| Contraste de color insuficienteHay texto de 18px con un contraste de 2.35:1 sobre su fondo, cuando la norma pide 4.5:1. | Grave | WCAG 1.4.3 (AA) · EN 301 549 9.1.4.3 |
| Falta la declaración de accesibilidadNo hemos encontrado ningún enlace a una declaración de accesibilidad en la página. | Grave | EN 301 549 Annex V |
| Texto alternativo sin informaciónHay imágenes cuyo alt es un nombre de archivo, un código o una palabra genérica como «imagen» o «foto». | Grave | WCAG 1.1.1 (A) · EN 301 549 9.1.1.1 |
| Marco incrustado sin títuloHay un <iframe> sin atributo title. | Grave | WCAG 4.1.2, 2.4.1 (A) · EN 301 549 9.4.1.2 |
| El placeholder hace de etiquetaHay campos cuyo único nombre accesible viene del atributo placeholder. | Grave | WCAG 3.3.2 (A) · EN 301 549 9.3.3.2 |
| Tabla de datos sin celdas de encabezadoHay una tabla con datos pero sin ninguna celda <th>. | Grave | WCAG 1.3.1 (A) · EN 301 549 9.1.3.1 |
| El indicador de foco está desactivadoEl CSS elimina el contorno del foco (a:focus) sin poner nada visible en su lugar. | Grave | WCAG 2.4.7 (AA) · EN 301 549 9.2.4.7 |
| Elemento clicable inalcanzable por tecladoHay un <div> con manejador de clic pero sin rol ni posición en el orden de tabulación. | Grave | WCAG 2.1.1, 4.1.2 (A) · EN 301 549 9.2.1.1 |
| Vídeo sin subtítulosHay un <video> sin pista de subtítulos. | Grave | WCAG 1.2.2 (A) · EN 301 549 9.1.2.2 |
| Contenido con sonido que se reproduce soloHay un <video> con autoplay sin silenciar. | Grave | WCAG 1.4.2 (A) · EN 301 549 9.1.4.2 |
| Falta el idioma del documentoEl elemento <html> no declara un idioma válido. | Grave | WCAG 3.1.1 (A) · EN 301 549 9.3.1.1 |
| La página impide ampliar con el zoomLa etiqueta viewport bloquea el zoom (width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no). | Grave | WCAG 1.4.4 (AA) · EN 301 549 9.1.4.4 |
| Enlaces con texto genéricoHay enlaces cuyo texto es «leer más», «clic aquí», «ver más» o equivalente. | Moderado | WCAG 2.4.4 (A) · EN 301 549 9.2.4.4 |
| Niveles de encabezado saltadosLa página pasa de un nivel de encabezado a otro saltándose los intermedios (de h1 a h4). | Moderado | WCAG 1.3.1 (A) · EN 301 549 9.1.3.1 |
| Rol ARIA inexistenteHay un elemento con role="buton", que no es un rol válido. | Moderado | WCAG 4.1.2 (A) · EN 301 549 9.4.1.2 |
| Atributo ARIA inexistenteHay un elemento con el atributo aria-labl, que no forma parte de la especificación. | Moderado | WCAG 4.1.2 (A) · EN 301 549 9.4.1.2 |
| tabindex con valor positivoHay elementos con tabindex="4". | Moderado | WCAG 2.4.3 (A) · EN 301 549 9.2.4.3 |
| Falta la región de contenido principalLa página no tiene <main>, o tiene más de uno. | Moderado | WCAG 1.3.1 (A) · EN 301 549 9.1.3.1 |
| Identificadores duplicadosEl identificador «col» aparece 3 veces. | Leve | WCAG 4.1.1 (A) · EN 301 549 9.4.1.1 |
Ahora · 0–7 días
Quitar los bloqueos
Publicar la declaración de accesibilidad y corregir lo marcado como crítico o grave. Es lo que impide comprar y lo que se ve desde fuera.
Siguiente ciclo
Arreglarlo en la plantilla
Lo moderado y lo leve suele venir del tema o de un componente repetido. Corregirlo ahí evita que vuelva con cada producto nuevo.
Validación
Probar la compra a mano
Recorrer ficha, carrito y pago con teclado y lector de pantalla. Ninguna herramienta automática cubre esa parte, y es donde se pierde la venta.
Qué hay que arreglar
Enlaces sin nombre
Crítico4 veces en esta página · WCAG 2.4.4, 4.1.2 (A) · EN 301 549 9.2.4.4, 9.4.1.2
Hay enlaces sin texto visible ni nombre accesible.
Por qué importa
Los lectores de pantalla permiten listar todos los enlaces de una página para navegar rápido. Un enlace sin nombre aparece en esa lista como la URL entera, o como «enlace» a secas. Suele pasar con los iconos de redes sociales del pie y con las tarjetas de producto donde solo la imagen es enlace.
Cómo se arregla
Dale texto visible, o si es un icono, un aria-label con el destino.
Así está <a href="https://instagram.com/tienda"><svg>…</svg></a>Así debería estar <a href="https://instagram.com/tienda" aria-label="Síguenos en Instagram"> <svg aria-hidden="true">…</svg> </a>Ver dónde ocurre
body.template-index > div.header:nth-of-type(1) > aLa imagen que lleva dentro no tiene atributo alt.
<a href="/"><img src="/cdn/shop/files/logo_final_v2.png"></a>body.template-index > div.grid:nth-of-type(3) > div.card:nth-of-type(1) > a:nth-of-type(1)La imagen que lleva dentro no tiene atributo alt.
<a href="/products/camiseta-arena"><img src="/cdn/shop/products/DSC_0042.jpg"></a>body.template-index > div.footer:nth-of-type(6) > div.social:nth-of-type(4) > a:nth-of-type(1)Solo hay un icono, sin título ni etiqueta.
<a href="https://instagram.com/tienda"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" /></svg></a>body.template-index > div.footer:nth-of-type(6) > div.social:nth-of-type(4) > a:nth-of-type(2)Solo hay un icono, sin título ni etiqueta.
<a href="https://facebook.com/tienda"><svg viewBox="0 0 24 24"><rect width="18" height="18" x="3" y="3" /></svg></a>
Campos de formulario sin etiqueta
Crítico1 vez en esta página · WCAG 1.3.1, 3.3.2, 4.1.2 (A) · EN 301 549 9.1.3.1, 9.3.3.2, 9.4.1.2
Hay campos de formulario sin nombre accesible: ni <label>, ni aria-label, ni aria-labelledby.
Por qué importa
Un campo sin etiqueta se anuncia como «cuadro de texto» y nada más. En un buscador es molesto; en la dirección de envío del checkout hace que la compra sea imposible de completar sin adivinar.
Un campo confuso en el checkout es un carrito abandonado. Esto no es solo cumplimiento: es conversión.
Cómo se arregla
Asocia un <label> con el atributo for al id del campo, o envuelve el campo dentro del label. El placeholder no cuenta: desaparece al escribir y muchos lectores de pantalla no lo anuncian.
En tu plataforma · Shopify
Los formularios del checkout de Shopify ya vienen etiquetados. Revisa los que has añadido tú: newsletter en el pie, buscador del cabecero y formularios de apps de terceros.
Así está <input type="email" name="email">Así debería estar <label for="email">Correo electrónico</label> <input type="email" id="email" name="email" autocomplete="email"> <!-- O envolviendo --> <label>Código postal <input type="text" name="cp" autocomplete="postal-code"> </label>Ver dónde ocurre
body.template-index > div.newsletter:nth-of-type(5) > form > input:nth-of-type(1)<input type="email" name="email">
Botones sin nombre
Crítico1 vez en esta página · WCAG 4.1.2 (A) · EN 301 549 9.4.1.2
Hay botones sin texto visible ni nombre accesible.
Por qué importa
Suele pasar con los botones de solo icono: la X de cerrar, la lupa de buscar, el carrito del cabecero. Un lector de pantalla los anuncia como «botón» y la persona tiene que activarlos para descubrir qué hacen.
Cómo se arregla
Si el botón tiene texto visible, ya está. Si es solo un icono, añade aria-label con la acción y marca el icono con aria-hidden="true".
En tu plataforma · Shopify
En el tema Dawn y derivados, los botones de icono del cabecero se editan en sections/header.liquid.
Así está <button><svg>…</svg></button>Así debería estar <button aria-label="Cerrar el aviso"> <svg aria-hidden="true">…</svg> </button>Ver dónde ocurre
body.template-index > div.header:nth-of-type(1) > button.cart-toggleSolo hay un icono, sin título ni etiqueta.
<button class="cart-toggle"><svg viewBox="0 0 24 24"><path d="M7 4h14l-2 9H8z" /></svg></button>
Contraste de color insuficiente
Grave4 veces en esta página · WCAG 1.4.3 (AA) · EN 301 549 9.1.4.3
Hay texto de 18px con un contraste de 2.35:1 sobre su fondo, cuando la norma pide 4.5:1.
Por qué importa
Es la barrera más extendida y la que más gente afecta: cualquiera con vista cansada, con el móvil al sol o con una pantalla mala. No hace falta tener una discapacidad reconocida para no poder leer un gris claro sobre blanco.
Los textos que suelen fallar son precisamente los que venden: precios tachados, gastos de envío, mensajes de stock.
Cómo se arregla
Oscurece el texto o aclara el fondo hasta alcanzar la proporción exigida. El texto normal necesita 4.5:1; a partir de 24 px (o 18.66 px en negrita) basta con 3:1. Los grises de tipo #999 sobre blanco casi nunca pasan.
En tu plataforma · Shopify
En el editor de temas, Configuración › Colores permite cambiar los esquemas de color del tema sin tocar código.
Así está /* 2.85:1 — no cumple */ .precio-antiguo { color: #999999; background: #ffffff; }Así debería estar /* 4.83:1 — cumple */ .precio-antiguo { color: #717171; background: #ffffff; }Ver dónde ocurre
body.template-index > div.hero:nth-of-type(2) > p.hero-sub<p class="hero-sub">Fabricada en España con algodón orgánico certificado.</p>body.template-index > div.grid:nth-of-type(3) > div.card:nth-of-type(1) > span.price-old:nth-of-type(1)<span class="price-old">29,00 €</span>body.template-index > div.grid:nth-of-type(3) > div.card:nth-of-type(1) > a:nth-of-type(2)<a href="/products/camiseta-arena">Leer más</a>body.template-index > div.footer:nth-of-type(6) > p.legal<p class="legal">© 2026 Tienda de ejemplo. Todos los derechos reservados.</p>
Falta la declaración de accesibilidad
Grave1 vez en esta página · EN 301 549 Annex V
No hemos encontrado ningún enlace a una declaración de accesibilidad en la página.
Por qué importa
La Ley 11/2023, que traspone la Directiva europea de accesibilidad, obliga a informar de cómo cumple el servicio los requisitos de accesibilidad. Es la parte que una autoridad de vigilancia puede comprobar sin abrir una sola herramienta técnica: mira el pie de página y, si no está, ya tiene un incumplimiento documentado.
Es el incumplimiento más barato de corregir y el más fácil de detectar desde fuera. Arreglarlo es una tarde; que te lo detecten es un expediente.
Cómo se arregla
Publica una página de accesibilidad y enlázala desde el pie, junto al aviso legal y la política de privacidad. Debe indicar el nivel de conformidad que declaras, qué partes sabes que aún no cumplen, la fecha de la última revisión y una vía de contacto para reportar barreras.
En tu plataforma · Shopify
Crea la página en Tienda online › Páginas y añádela al menú del pie en Navegación.
Así está <footer> <a href="/aviso-legal">Aviso legal</a> <a href="/privacidad">Privacidad</a> </footer>Así debería estar <footer> <a href="/aviso-legal">Aviso legal</a> <a href="/privacidad">Privacidad</a> <a href="/accesibilidad">Declaración de accesibilidad</a> </footer>Texto alternativo sin información
Grave1 vez en esta página · WCAG 1.1.1 (A) · EN 301 549 9.1.1.1
Hay imágenes cuyo alt es un nombre de archivo, un código o una palabra genérica como «imagen» o «foto».
Por qué importa
Un alt que dice «DSC_0042.jpg» o «producto» cumple la forma pero no la función: la persona sigue sin saber qué hay en la imagen. Suele pasar cuando el catálogo se importó de golpe y se rellenó el campo automáticamente.
Cómo se arregla
Describe el contenido concreto. Para producto, la fórmula que funciona es: qué es + característica distintiva + variante. «Camiseta de algodón orgánico color arena» sirve; «producto» no.
En tu plataforma · Shopify
Si importaste el catálogo con un CSV, revisa la columna «Image Alt Text» y vuelve a importar con descripciones reales en lugar del nombre de archivo.
Así está <img src="/p1.jpg" alt="imagen"> <img src="/p2.jpg" alt="DSC_0042.jpg">Así debería estar <img src="/p1.jpg" alt="Zapatilla de running gris con suela naranja"> <img src="/p2.jpg" alt="Mochila de lona negra de 20 litros, vista lateral">Ver dónde ocurre
body.template-index > div.grid:nth-of-type(3) > div.card:nth-of-type(2) > a:nth-of-type(1) > img<img src="/cdn/shop/products/sudadera.jpg" alt="imagen">
Marco incrustado sin título
Grave1 vez en esta página · WCAG 4.1.2, 2.4.1 (A) · EN 301 549 9.4.1.2
Hay un <iframe> sin atributo title.
Por qué importa
Al navegar por lectores de pantalla se pueden listar los marcos de la página. Sin título aparecen como «marco», «marco», «marco», y hay que entrar en cada uno para saber cuál es el vídeo, cuál el mapa y cuál el chat.
Es una corrección de treinta segundos por marco y sale en todos los informes de auditoría.
Cómo se arregla
Añade un title que describa qué contiene el marco. Si el iframe es un píxel de seguimiento invisible, márcalo con aria-hidden="true" además de ocultarlo.
En tu plataforma · Shopify
Si el vídeo viene de un bloque del tema, edita la plantilla en Tienda online › Temas › Editar código y añade el title al iframe.
Así está <iframe src="https://www.youtube.com/embed/xyz"></iframe>Así debería estar <iframe src="https://www.youtube.com/embed/xyz" title="Vídeo: cómo elegir tu talla"></iframe>Ver dónde ocurre
body.template-index > iframe<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" width="560" height="315"></iframe>
El placeholder hace de etiqueta
Grave1 vez en esta página · WCAG 3.3.2 (A) · EN 301 549 9.3.3.2
Hay campos cuyo único nombre accesible viene del atributo placeholder.
Por qué importa
El texto del placeholder desaparece en cuanto la persona empieza a escribir. Quien se distrae a mitad de un formulario ya no puede saber qué iba en ese campo, y quien tiene dificultades de memoria o atención se queda sin referencia. Además su contraste suele ser bajísimo por diseño.
Cómo se arregla
Añade un <label> visible. Puedes mantener el placeholder como ejemplo del formato («ej. 28001»), pero nunca como sustituto del nombre del campo.
Así está <input type="text" name="cp" placeholder="Código postal">Así debería estar <label for="cp">Código postal</label> <input type="text" id="cp" name="cp" placeholder="ej. 28001" autocomplete="postal-code">Ver dónde ocurre
body.template-index > div.header:nth-of-type(1) > form.search > input<input type="text" name="q" placeholder="Buscar productos">
Tabla de datos sin celdas de encabezado
Grave1 vez en esta página · WCAG 1.3.1 (A) · EN 301 549 9.1.3.1
Hay una tabla con datos pero sin ninguna celda <th>.
Por qué importa
En una tabla bien marcada, el lector de pantalla anuncia «Talla: M, Precio: 19 €» al moverse por las celdas. Sin encabezados solo lee «M, 19 €», y la persona tiene que recordar el orden de las columnas.
Cómo se arregla
Convierte la primera fila (o columna) en <th> y añade scope="col" o scope="row".
En tu plataforma · Shopify
Las tablas de guía de tallas suelen escribirse en el editor enriquecido de la descripción del producto; edita el HTML desde el botón «</>».
Así está <tr><td>Talla</td><td>Precio</td></tr> <tr><td>M</td><td>19 €</td></tr>Así debería estar <tr><th scope="col">Talla</th><th scope="col">Precio</th></tr> <tr><td>M</td><td>19 €</td></tr>Ver dónde ocurre
body.template-index > div.sizes:nth-of-type(4) > table<table> <tr><td>Talla</td><td>Pecho</td><td>Largo</td></tr> <tr><td>S</td><td>96 cm</td><td>68 cm</td></tr> <tr><td>M</td><td>101 cm</td><td>70 cm</td></tr> </table>
El indicador de foco está desactivado
Grave1 vez en esta página · WCAG 2.4.7 (AA) · EN 301 549 9.2.4.7
El CSS elimina el contorno del foco (a:focus) sin poner nada visible en su lugar.
Por qué importa
Quien navega con el tabulador necesita ver dónde está. Sin indicador de foco, la persona pulsa Tab y no sabe qué elemento tiene seleccionado: navegar se vuelve adivinar. Es de los fallos más incapacitantes y de los más fáciles de arreglar.
Un solo `outline: none` en el CSS del tema puede hacer inoperable toda la tienda por teclado.
Cómo se arregla
Nunca uses outline: none sin sustituto. Si el contorno por defecto no encaja con el diseño, dibuja el tuyo, con un contraste de al menos 3:1 contra el fondo.
Así está a:focus, button:focus { outline: none; }Así debería estar a:focus-visible, button:focus-visible { outline: 3px solid #005fcc; outline-offset: 2px; }Ver dónde ocurre
a:focusa:focus { outline: none }
Elemento clicable inalcanzable por teclado
Grave1 vez en esta página · WCAG 2.1.1, 4.1.2 (A) · EN 301 549 9.2.1.1
Hay un <div> con manejador de clic pero sin rol ni posición en el orden de tabulación.
Por qué importa
El ratón puede hacer clic en cualquier cosa; el teclado no. Un <div> con onclick es invisible para quien navega con tabulador, con conmutador o con control por voz. Si ese div es «Añadir al carrito», la tienda no es utilizable.
Es el fallo que con más frecuencia deja un checkout completamente bloqueado.
Cómo se arregla
Usa <button>. Resuelve el foco, la activación con Enter y espacio, y el anuncio del rol, todo de una vez y sin JavaScript adicional.
Así está <div onclick="anadirAlCarrito()">Añadir al carrito</div>Así debería estar <button type="button" onclick="anadirAlCarrito()">Añadir al carrito</button>Ver dónde ocurre
body.template-index > div.hero:nth-of-type(2) > div.cta<div class="cta" onclick="location.href='/collections/novedades'">Ver la colección</div>
Vídeo sin subtítulos
Grave1 vez en esta página · WCAG 1.2.2 (A) · EN 301 549 9.1.2.2
Hay un <video> sin pista de subtítulos.
Por qué importa
Sin subtítulos, el vídeo no existe para quien no oye. Y tampoco para la mayoría de gente que navega con el móvil en silencio, que es casi todo el mundo.
Cómo se arregla
Añade un <track kind="captions"> con un archivo WebVTT. Si el vídeo está alojado en YouTube o Vimeo, activa los subtítulos allí y revísalos: los automáticos suelen tener errores.
Así está <video src="/promo.mp4" controls></video>Así debería estar <video src="/promo.mp4" controls> <track kind="captions" src="/promo-es.vtt" srclang="es" label="Español" default> </video>Ver dónde ocurre
body.template-index > div.hero:nth-of-type(2) > video<video src="/cdn/shop/videos/hero.mp4" autoplay loop></video>
Contenido con sonido que se reproduce solo
Grave1 vez en esta página · WCAG 1.4.2 (A) · EN 301 549 9.1.4.2
Hay un <video> con autoplay sin silenciar.
Por qué importa
El audio inesperado se superpone a la voz del lector de pantalla y hace ilegible la página hasta que se consigue parar. Encontrar el botón de pausa sin ver la pantalla, mientras suena, es exactamente lo difícil que parece.
Cómo se arregla
Quita el autoplay, o añade muted. Si necesitas reproducción automática, que dure menos de tres segundos o que tenga un control de parada visible al principio de la página.
Así está <video src="/hero.mp4" autoplay loop></video>Así debería estar <video src="/hero.mp4" autoplay loop muted playsinline></video>Ver dónde ocurre
body.template-index > div.hero:nth-of-type(2) > video<video src="/cdn/shop/videos/hero.mp4" autoplay loop></video>
Falta el idioma del documento
Grave1 vez en esta página · WCAG 3.1.1 (A) · EN 301 549 9.3.1.1
El elemento <html> no declara un idioma válido.
Por qué importa
El lector de pantalla elige la voz y la pronunciación según ese atributo. Sin él, una tienda en español puede leerse con fonética inglesa: «camiseta» suena a «kam-eye-set-ah» y no se entiende nada.
Corrección de treinta segundos con impacto en toda la web. Empieza por aquí.
Cómo se arregla
Añade lang="es" al elemento <html>. Es un atributo, en una línea, y arregla la página entera.
En tu plataforma · Shopify
En layout/theme.liquid, la primera línea debe ser <html lang="{{ request.locale.iso_code }}">.
Así está <html>Así debería estar <html lang="es">La página impide ampliar con el zoom
Grave1 vez en esta página · WCAG 1.4.4 (AA) · EN 301 549 9.1.4.4
La etiqueta viewport bloquea el zoom (width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no).
Por qué importa
Mucha gente amplía la pantalla del móvil para leer. Bloquearlo por motivos de diseño les deja sin acceso al contenido, sin más. La norma exige poder ampliar al menos al 200 %.
Cómo se arregla
Quita user-scalable=no y cualquier maximum-scale menor que 2.
Así está <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">Así debería estar <meta name="viewport" content="width=device-width, initial-scale=1">Ver dónde ocurre
head > meta:nth-of-type(2)<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
Enlaces con texto genérico
Moderado2 veces en esta página · WCAG 2.4.4 (A) · EN 301 549 9.2.4.4
Hay enlaces cuyo texto es «leer más», «clic aquí», «ver más» o equivalente.
Por qué importa
Fuera de contexto ese texto no dice nada. En la lista de enlaces que genera un lector de pantalla, una página de categoría se convierte en veinte entradas idénticas que dicen «leer más».
El texto del enlace es una de las señales que usa Google para entender la página de destino. «Leer más» no le dice nada tampoco a él.
Cómo se arregla
Escribe el destino en el propio enlace: «Ver la camiseta de algodón orgánico». Si el diseño exige mantener «Leer más» visible, añade un aria-label completo.
Así está <h3>Camiseta arena</h3> <a href="/p/1">Leer más</a>Así debería estar <h3>Camiseta arena</h3> <a href="/p/1" aria-label="Ver la camiseta arena">Leer más</a> <!-- Mejor todavía --> <a href="/p/1">Ver la camiseta arena</a>Ver dónde ocurre
body.template-index > div.grid:nth-of-type(3) > div.card:nth-of-type(1) > a:nth-of-type(2)<a href="/products/camiseta-arena">Leer más</a>body.template-index > div.grid:nth-of-type(3) > div.card:nth-of-type(2) > a:nth-of-type(2)<a href="/products/sudadera-gris">Leer más</a>
Niveles de encabezado saltados
Moderado1 vez en esta página · WCAG 1.3.1 (A) · EN 301 549 9.1.3.1
La página pasa de un nivel de encabezado a otro saltándose los intermedios (de h1 a h4).
Por qué importa
Los encabezados son el índice con el que se navega una página con lector de pantalla. Si los niveles saltan, ese índice deja de reflejar la jerarquía real y la persona no sabe si la sección nueva depende de la anterior o empieza de cero.
Cómo se arregla
Usa los niveles en orden. Si saltas un nivel por el tamaño de letra, cambia el nivel al correcto y ajusta el tamaño con CSS.
Así está <h1>Tienda</h1> <h4>Ofertas</h4>Así debería estar <h1>Tienda</h1> <h2 class="titulo-pequeno">Ofertas</h2>Ver dónde ocurre
body.template-index > h4<h4>Más vendidos</h4>
Rol ARIA inexistente
Moderado1 vez en esta página · WCAG 4.1.2 (A) · EN 301 549 9.4.1.2
Hay un elemento con role="buton", que no es un rol válido.
Por qué importa
Un rol mal escrito no hace nada: el navegador lo ignora y el elemento se expone con su semántica original, que casi siempre es «ningún significado». El desarrollador cree haberlo arreglado y no lo ha hecho.
Cómo se arregla
Corrige el nombre del rol, o quítalo y usa el elemento HTML nativo correspondiente, que ya trae el rol correcto.
Así está <span role="buton">Comprar</span>Así debería estar <button type="button">Comprar</button>Ver dónde ocurre
body.template-index > span<span role="buton" aria-labl="ayuda" tabindex="4">Ayuda</span>
Atributo ARIA inexistente
Moderado1 vez en esta página · WCAG 4.1.2 (A) · EN 301 549 9.4.1.2
Hay un elemento con el atributo aria-labl, que no forma parte de la especificación.
Por qué importa
Igual que con los roles inventados: el navegador lo descarta en silencio. Suelen ser erratas (aria-labl, aria-describe) que dejan el elemento sin el nombre o la descripción que se pretendía darle.
Cómo se arregla
Revisa la ortografía del atributo contra la especificación WAI-ARIA.
Ver dónde ocurre
body.template-index > span<span role="buton" aria-labl="ayuda" tabindex="4">Ayuda</span>
tabindex con valor positivo
Moderado1 vez en esta página · WCAG 2.4.3 (A) · EN 301 549 9.2.4.3
Hay elementos con tabindex="4".
Por qué importa
Un tabindex positivo saca al elemento de su sitio en el orden de tabulación y lo pone antes que todo lo demás. El resultado es que el foco salta por la página en un orden que no se corresponde con lo que se ve, y a medida que la página crece se vuelve imposible de mantener.
Cómo se arregla
Usa tabindex="0" para hacer focalizable un elemento, o tabindex="-1" para poder enfocarlo por programación. Si el orden no es el correcto, cambia el orden del HTML.
Ver dónde ocurre
body.template-index > span<span role="buton" aria-labl="ayuda" tabindex="4">Ayuda</span>
Falta la región de contenido principal
Moderado1 vez en esta página · WCAG 1.3.1 (A) · EN 301 549 9.1.3.1
La página no tiene <main>, o tiene más de uno.
Por qué importa
El atajo «ir al contenido principal» es la forma más rápida de saltarse el menú, que se repite igual en todas las páginas. Sin <main> ese atajo no existe y hay que tabular por el menú entero cada vez.
Cómo se arregla
Envuelve el contenido propio de la página (no el cabecero, el menú ni el pie) en un único <main>.
Identificadores duplicados
Leve1 vez en esta página · WCAG 4.1.1 (A) · EN 301 549 9.4.1.1
El identificador «col» aparece 3 veces.
Por qué importa
Las referencias de accesibilidad (label for, aria-labelledby, aria-describedby) apuntan a un id y siempre resuelven al primero que encuentran. Con ids duplicados, la etiqueta de un campo puede acabar describiendo otro.
Cómo se arregla
Haz único cada id. Si viene de un componente repetido, añádele un sufijo con el índice o el identificador del producto.
Ver dónde ocurre
#col<div id="col"><a href="/pages/privacidad">Política de privacidad</a></div>
Para revisar a mano
Referencia ARIA a un identificador que no existe
El atributo aria-labelledby apunta a los identificadores titulo-inexistente, que no están en la página.
Comprueba que el id existe y coincide exactamente, mayúsculas incluidas. Si el elemento de destino ya no existe, sustituye la referencia por un aria-label.
Campos de datos personales sin autocomplete
Hay campos que piden datos personales habituales (correo, teléfono, dirección) sin atributo autocomplete.
Añade el token estándar correspondiente: autocomplete="email" en este caso.
Campo obligatorio solo indicado visualmente
La etiqueta del campo indica que es obligatorio (con un asterisco o con la palabra), pero el campo no lo declara con required ni aria-required.
Añade el atributo required al campo. Mantén también la indicación visual: las dos cosas, no una u otra.
Faltan regiones de referencia
La página no marca alguna de sus regiones principales: navigation, banner, contentinfo.
Usa las etiquetas semánticas correctas: <header>, <nav>, <main> y <footer>, en lugar de <div class="header">.
Texto extremadamente pequeño
Hay texto por debajo de 10 px (9px).
Sube a 12 px como mínimo, y a 16 px en el contenido principal. Usa unidades relativas (rem) para que respete los ajustes del navegador.
Lo que ya está bien
- Imágenes sin texto alternativo
- Texto alternativo redundante
- Icono SVG con significado pero sin nombre
- Enlaces que muestran la URL completa
- Falta el encabezado principal, o hay más de uno
- La página no tiene encabezados
- Encabezados vacíos
- Elemento con rol interactivo pero sin nombre
- Título de página ausente o vacío
Hasta dónde llega este informe
Hemos analizado una sola página, con el HTML y el CSS que sirve el servidor. No ejecutamos JavaScript, así que lo que se genera después de cargar (menús desplegables, modales, pasos del checkout) no entra. Y ninguna herramienta automática cubre más del 30-40 % de los criterios WCAG: el resto exige que una persona pruebe la tienda con teclado y lector de pantalla.
Referencias
- EN 301 549 V3.2.1 — Accessibility requirements for ICT products and services
- W3C — Web Content Accessibility Guidelines (WCAG) 2.1
- Directiva (UE) 2019/882 — European Accessibility Act
Este informe no constituye asesoramiento jurídico.
¿Te mandamos esto por escrito?
Te enviamos este informe en PDF, por qué orden conviene arreglarlo y un aviso si la ley cambia en algo que te afecte. Lo escribe una persona, no es un boletín automático, y no compartimos tu dirección con nadie.
Vigila que no vuelva a romperse
Cada cambio de tema, cada app nueva y cada producto importado puede reintroducir estas barreras. Con el seguimiento analizamos tu tienda entera cada semana, te avisamos si algo empeora y guardamos el histórico con fecha, que es justo lo que se enseña si alguien pregunta.
Ver planes