- Una card clicable necesita un enlace real con un nombre descriptivo; lo demás es hacer que el clic en cualquier parte de la tarjeta lo active.
- Envolver todo en un
<a>es HTML válido mientras no haya contenido interactivo dentro, pero el nombre del enlace pasa a ser la tarjeta entera: 81 caracteres en mi prueba frente a 13 con el enlace en el título. - El patrón que recomiendo es el stretched link: enlace en el título y un
::afterabsoluto que cubre la tarjeta. En mi laboratorio, el 100 % de la tarjeta lleva al destino con una sola parada de tabulador. - Los «Leer más» repetidos incumplen el criterio WCAG 2.4.4 si no tienen contexto programático. Se resuelve con el nombre del enlace, no con un segundo enlace.
- Google documenta que usa el texto del enlace y, en imágenes enlazadas, el
alt. Lo que hace con un ancla que contiene título, párrafo y botón no está documentado. - En mi propia web encontré una zona muerta en las blog cards: el texto «Leer el artículo» no navegaba al hacer clic. Lo he corregido y he vuelto a medir: 6 de 6 clics sobre ese texto y 6 de 6 sobre su icono de flecha llevan al artículo.
Una tarjeta de blog, de categoría o de servicio suele tener una imagen, un título, un extracto y una llamada a la acción. Lo habitual es meterlo todo dentro de un <a> para que sea clicable, y el resultado es un enlace cuyo texto ancla es un párrafo entero, con un lector de pantalla que lo lee de corrido y, si hay un botón dentro, un HTML que ya no es válido.
Aquí separo lo que está documentado de lo que es costumbre de maquetación. He montado cinco patrones en un laboratorio, los he medido con Playwright en Chromium 141 (clic, foco, árbol de accesibilidad) y he repetido las mediciones sobre las cards reales de mi web, con unos hallazgos incómodos, algunos ya corregidos y otros que sigo teniendo.

Qué es una card box y qué se rompe al enlazarla
Una card box (o simplemente card) es un bloque que agrupa varios elementos sobre un mismo destino: imagen, categoría, título, texto y una llamada a la acción. Aparece en listados de blog, categorías de ecommerce, casos de éxito y bloques de artículos relacionados. Desde el punto de vista del enlazado, es la plantilla que se repite decenas de veces por página, así que cualquier defecto se multiplica. Si trabajas la arquitectura de enlaces del sitio, como explico en la guía de enlazado interno, las cards son uno de los sitios donde más enlaces internos se generan.
Hay tres cosas que se pueden romper a la vez:
- El texto del enlace. Si el ancla contiene todo el bloque, pasa a ser una mezcla de título, extracto y botón.
- La accesibilidad. Un lector de pantalla anuncia el enlace entero, y un segundo enlace o un botón generan paradas duplicadas o enlaces anidados.
- El área de clic. Si enlazas solo el título, el resto de la tarjeta parece clicable y no lo es.
Qué documenta Google sobre enlaces y anclas
La documentación de Google sobre enlaces rastreables dice tres cosas que importan aquí. Que, en general, solo puede rastrear un enlace si es un elemento <a> con atributo href. Que el texto del enlace dice algo a las personas y a Google sobre la página enlazada, y que conviene que sea descriptivo. Y que, cuando el enlace es una imagen, Google usa el atributo alt del <img> como texto ancla; si el enlace está vacío, puede recurrir al atributo title.
Lo que esa página no documenta es cómo trata un ancla que contiene un encabezado, un párrafo y un botón. No hay una cifra de longitud máxima ni una regla sobre ancla «infinita». Un artículo de Ahrefs en español (abril de 2025) sostiene que el enlace envolvente genera un anchor text desmesurado y propone poner el enlace en el título con un ::after; es una recomendación razonable, pero la parte sobre cómo lo procesa Google es, hasta donde he podido ver, una inferencia del autor y no una afirmación de Google. No puedo demostrar que el patrón envolvente penalice, y tampoco hace falta: los argumentos de accesibilidad bastan.
Lo que sí controlas: si la card tiene una imagen enlazada, su alt será ancla (lo desarrollo en la guía de texto alternativo), y el enlace debe ser un <a href> real. Una tarjeta que navega solo con un onclick, sin href, va contra lo que Google dice poder rastrear de forma fiable; lo explico en la guía de SEO para JavaScript.
El enlace envolvente: válido, pero con letra pequeña
Este es el patrón más frecuente: <a href="/post/"> abre antes de la imagen y se cierra después del botón. Mi laboratorio lo reproduce así:
<article class="card">
<a href="/p/a/">
<img src="x.png" alt="Portada del artículo sobre cards">
<h3>Guía de cards</h3>
<p>Cómo hacer clicable una tarjeta sin romper la accesibilidad.</p>
<button type="button">Leer más</button>
</a>
</article>
Hay un matiz que se suele contar mal. Según la especificación HTML, el contenido de <a> es transparente y puede envolver párrafos, listas, tablas e incluso secciones enteras. Lo que no puede tener es contenido interactivo dentro (otro enlace, un botón, un campo de formulario) ni descendientes con tabindex. Dicho de otro modo: envolver un <h3>, un <p> y un <span> es válido; envolver un <button> no lo es.
El navegador, eso sí, no te avisa. En mi prueba, el HTML con el botón dentro se conservó tal cual, el clic sobre el botón navegó al destino del enlace y el teclado encontró dos paradas en esa tarjeta (el enlace y el botón). El caso del enlace dentro del enlace es peor: al insertar <a href="/1">uno <a href="/2">dos</a> tres</a>, Chromium cierra el primer enlace al abrir el segundo y el texto «tres» se queda fuera de cualquier enlace.

El nombre del enlace es la tarjeta entera
El segundo problema está en lo que se anuncia. En el árbol de accesibilidad de Chromium, el enlace envolvente de mi laboratorio se llamaba «Portada del artículo sobre cards Guía de cards Cómo hacer clicable una tarjeta sin romper la accesibilidad. Leer más». El texto visible de la tarjeta tenía 81 caracteres; con el enlace en el título, el nombre era «Guía de cards», 13.

Para una persona que navega con lector de pantalla y consulta la lista de enlaces de la página, esa diferencia es la que separa una lista usable de una lista de párrafos. Para el SEO no puedo afirmar nada con datos, pero la guía de Google, que pide anclas descriptivas, apunta en la misma dirección.
Comparativa de patrones
Esto es lo que midió el laboratorio con la misma tarjeta (imagen, título, texto y llamada a la acción), en un viewport de 1100 px:
| Patrón | Texto del ancla | Paradas de tabulador | Clic en toda la tarjeta | Seleccionar texto |
|---|---|---|---|---|
| Enlace envolvente con botón dentro | 81 caracteres | 2 | Sí | No probado |
| Solo el título | 13 caracteres | 1 | No: el 3 % del área | Sí (31 caracteres) |
| Stretched link | 13 caracteres | 1 | Sí: 100 % | No (0 caracteres) |
| Stretched link con enlace secundario elevado | 13 y 14 | 2 | Sí; el secundario funciona | No probado |
| Proxy con JavaScript | 13 caracteres | 1 | Sí, con clic corto | Sí (31 caracteres) |

La tabla deja ver el compromiso. Enlazar solo el título es limpio pero deja el 97 % de la tarjeta sin respuesta. El stretched link lo arregla sin JavaScript, a cambio de que no se pueda seleccionar texto arrastrando sobre la tarjeta. El proxy con JavaScript conserva la selección, pero depende de un script para algo que el navegador sabe hacer solo.
El patrón que recomiendo: enlace en el título y capa estirada
El enlace vive en el título, que es el texto más descriptivo de la tarjeta. Un pseudo-elemento ::after de ese enlace, con posición absoluta y inset: 0, se extiende hasta los bordes del contenedor posicionado y captura el clic. Es la técnica que describe Heydon Pickering en Inclusive Components y que Bootstrap incluye como .stretched-link. Este es el código que probé:
<article class="card">
<img src="portada.webp" alt="" width="800" height="450">
<h3><a href="/p/c/">Guía de cards</a></h3>
<p>Cómo hacer clicable una tarjeta sin romper la accesibilidad.</p>
<span class="btn" aria-hidden="true">Leer más</span>
</article>
.card { position: relative; }
.card h3 a::after {
content: "";
position: absolute;
inset: 0;
}
.card:hover,
.card:focus-within { box-shadow: 0 0 0 3px #3fa9e0; }
.card h3 a:focus-visible { outline: 3px solid #f25cf0; outline-offset: 4px; }
Con este HTML, el clic sobre la imagen, el párrafo, el pseudo-botón y el título llevó al mismo destino, y el árbol de accesibilidad mostró un encabezado de nivel 3 con un enlace «Guía de cards» y un párrafo, sin más enlaces. El botón decorativo es un <span> con aria-hidden="true": si fuera un <a> al mismo destino, tendrías dos enlaces iguales por tarjeta.

Enlaces secundarios dentro de la card
Si la tarjeta tiene otro enlace (el autor, una categoría), la capa estirada lo tapa. Lo comprobé: sin z-index, el clic sobre «Cristofer Cruz» fue a /p/e/, el destino de la tarjeta, no a /autor/cristofer/. La solución es elevar el secundario con position: relative; z-index: 2;; con eso, el clic fue a su propio destino y la tarjeta quedó con dos paradas de tabulador. Pickering lo resume con una frase que suscribo: las cards no deberían ser páginas en miniatura. Cada enlace extra es una parada más para quien navega con teclado.
Dónde falla el stretched link
La documentación de Bootstrap recoge varias limitaciones que conviene tener a mano. El contenedor debe estar posicionado, porque el área se calcula contra el bloque contenedor más cercano; un transform, filter o perspective en un ancestro cambia ese bloque contenedor y el enlace cubre solo ese elemento. Dar position: relative al propio enlace rompe el estirado. Y no funciona con elementos de tabla. Pickering añade la limitación que medí: la capa tapa el texto y no se puede seleccionar.
Los «Leer más» repetidos y el criterio 2.4.4
Una página con diez tarjetas y diez enlaces «Leer más» es una lista de enlaces idénticos para un lector de pantalla. El criterio 2.4.4 de WCAG 2.2 (Propósito de los enlaces en contexto, nivel A) pide que el propósito de cada enlace pueda determinarse a partir del texto del enlace o del texto del enlace junto con su contexto determinado por programa. W3C incluye como contexto el texto de la misma frase, párrafo, elemento de lista o celda de tabla, y el que se vincula mediante aria-label o aria-labelledby. Añade que los enlaces con el mismo destino deberían usar el mismo texto y los de destino distinto, textos distintos.
Medí en Chromium cómo se calcula el nombre en cinco variantes:
| Variante | Nombre accesible | Descripción |
|---|---|---|
| Solo «Leer más» | Leer más | Ninguna |
aria-describedby apuntando al h3 | Leer más | Guía de cards |
aria-label="Leer más: Guía de cards" | Leer más: Guía de cards | Ninguna |
Texto visually-hidden con el título | Leer más : Guía de cards | Ninguna |
aria-labelledby al propio enlace y al h3 | Leer más Guía de cards | Ninguna |

La opción más simple es la que mejor funciona: que el enlace principal sea el título y que no exista un «Leer más» enlazado. Si tu diseño exige el texto, mantenlo como elemento decorativo dentro del patrón estirado, o hazlo un enlace con el título oculto con una clase visually-hidden para que su nombre diga «Leer más: título». Evita aria-label con un texto distinto del visible, porque el nombre accesible deja de coincidir con lo que la persona ve; en el caso de arriba, el texto visible sigue contenido en el nombre, pero no me apoyaría en eso sin comprobarlo.
Si las tarjetas son una lista de elementos, maquétalas como <ul> con <li>. Según W3C, el texto del mismo elemento de lista cuenta como contexto del enlace para el criterio 2.4.4.
La imagen de la card: alt vacío o descriptivo
Si la imagen está dentro de la zona estirada y el enlace principal es el del título, la imagen es decorativa: alt="". Su información ya está en el título y no quieres que el lector de pantalla la anuncie dos veces. Si la imagen fuera el único enlace de la tarjeta (una galería sin texto), el alt pasa a ser el ancla y debe describir el destino, no la fotografía.
Un detalle de rendimiento: las imágenes de cards suelen cargar en loading="lazy". Pon siempre width y height (o aspect-ratio) para evitar saltos de maquetación; en el contexto de las Core Web Vitals, una rejilla de cards que reserva su hueco no mueve el contenido al cargar.
La alternativa con JavaScript
El patrón de Pickering mide el tiempo entre mousedown y mouseup y suprime el clic si pasa de unos 200 ms, para no disparar la navegación cuando alguien está seleccionando texto. Mi versión del laboratorio añade una segunda comprobación: si hay texto seleccionado, no navega.
document.querySelectorAll('.card').forEach(card => {
let t = 0;
card.addEventListener('mousedown', () => t = Date.now());
card.addEventListener('click', e => {
if (e.target.closest('a')) return;
if (Date.now() - t > 200) return;
if (getSelection().toString()) return;
card.querySelector('h3 a').click();
});
});
En el laboratorio, un clic corto sobre el párrafo y sobre la imagen llevó al destino, la selección de texto por arrastre funcionó (31 caracteres seleccionados sin navegar) y el enlace del título seguía siendo la única parada de teclado. La ventaja es que el enlace real sigue en el HTML. El coste es mantener JavaScript para algo que CSS resuelve, y que si el script falla, el clic en el cuerpo de la tarjeta no hace nada.
Cómo lo tengo en mi web
Medí las cards reales de cristofercruz.net en Chromium 141 con un viewport de 1280 px y el banner de cookies oculto para que no tapase la rejilla. Muestreé 1.600 puntos por tarjeta y registré cuántos caían sobre un enlace. Hice la medición dos veces: la primera, antes de corregir nada, y la segunda, con el CSS ya cambiado. Donde las cifras difieren, lo indico.
| Card | Cómo está enlazada | Medición |
|---|---|---|
| Blog (listado y artículos relacionados) | Enlace en el h3 con ::after estirado; imagen con alt=""; «Leer el artículo» es un span sin position | 1 enlace por card, nombre = título (49 a 80 caracteres según el título del artículo). 100 % del área lleva al artículo (antes, el 94 %) |
| Servicios (home) | Enlace «Ver …» con ::before estirado; el título no es enlace | 100 % del área; nombre «Ver Consultoría SEO», por ejemplo |
| Servicios relacionados | <a> envolvente con h3, p y span | Nombre de 88 a 111 caracteres; 100 % |
| Casos de éxito (listado) | <a> envolvente con etiqueta, h3, texto y cifra | Nombre de 172 a 269 caracteres; 100 % |
| Casos (home) y página de servicios | Solo el botón es enlace | 2 % y 8 % del área |

Lo que está bien resuelto
Las blog cards siguen el patrón que recomiendo: enlace en el título, imagen decorativa y una sola parada de tabulador por tarjeta, con el nombre del enlace igual al título. El foco se ve: Chromium devolvió un contorno sólido de 3 px sobre el enlace del título. Y no hay «Leer más» repetidos como enlaces: el texto «Leer el artículo» lleva el título del artículo en un texto oculto, pero no es un enlace.
Lo que corregí y lo que sigo teniendo
- Zona muerta en las blog cards (corregida). El
span«Leer el artículo» teníaposition: relativey quedaba por encima de la capa estirada. Al hacer clic sobre ese texto en la tarjeta del artículo de caché, la página se quedó en/blog/; sobre la imagen, el título, el extracto, la categoría y la fecha, navegó a/blog/cache-seo/. En el muestreo era el 6 % del área. Quité esa declaración del CSS y repetí la prueba: el muestreo da 1.600 de 1.600 puntos sobre el enlace (100 %) y el clic sobre «Leer el artículo» lleva al artículo en las 6 cards del listado. Una primera corrección dejó sin navegar el icono de flecha de 18 × 18 px (2 de 1.600 puntos): es un pseudo-elemento con máscara, que crea su propio contexto de apilamiento y se pintaba por encima de la capa estirada. Conpointer-events: noneen ese icono, el clic sobre la flecha también navega en las 6 cards. - Nombres larguísimos en las cards envolventes (sigue así). Las tarjetas de servicios relacionados tienen entre 88 y 111 caracteres de nombre accesible y las de casos de éxito, entre 172 y 269 (222 de media). Esa longitud es el mismo problema que mostré antes, a escala de mi propio sitio. Las blog cards, con el patrón estirado, están entre 49 y 80.
- Los botones de caso de éxito y de servicio son la única zona clicable (sigue así). En la home, entre el 2 y el 3 % del área de la tarjeta lleva al caso, y en la página de servicios, el 8 %. Es una decisión de diseño legítima.
- URLs absolutas en las cards de casos (corregido). Los enlaces de las cards de casos de éxito salían como
https://cristofercruz.net/casos-de-exito/…mientras el resto eran relativos a la raíz. Ahora los datos de los casos usan/casos-de-exito/…y, en la medición, todos los enlaces de las cards son relativos a la raíz. Las diferencias entre ambos tipos las explico en el artículo de URLs absolutas y relativas. - No hay listas (sigue así). Las rejillas de cards son
divconarticledentro, noulconli.
Lo que no he medido: Safari, Firefox, lectores de pantalla reales (NVDA, VoiceOver, JAWS) ni el comportamiento en táctil.
Móvil y tamaño del área táctil
Una tarjeta entera clicable es, de partida, un buen objetivo táctil. El criterio 2.5.8 de WCAG 2.2 (nivel AA) pide objetivos de al menos 24 por 24 píxeles CSS, con excepciones para enlaces dentro de una frase, y MDN recomienda un mínimo de 44 por 44. Con el enlace solo en el título, el objetivo suele ser una línea de texto; con el stretched link, es toda la tarjeta. Si trabajas la experiencia en pantallas pequeñas, esto enlaza con lo que cuento en la guía de SEO móvil. Separa los enlaces secundarios con margen y no dependas de :hover para indicar que algo es clicable: en táctil no existe.
Cómo auditar las cards de una web
La comprobación lleva cinco minutos por tipo de card y no necesita herramientas de pago. La hago así:
- Cuenta los enlaces por tarjeta. En DevTools, pestaña de accesibilidad o consola:
document.querySelectorAll('.card a[href]'). Lo normal es uno; más de uno exige un motivo. - Lee el nombre de cada enlace. En el árbol de accesibilidad, un nombre que sea «Leer más», una URL o un párrafo es un fallo.
- Haz clic en los rincones. Imagen, extracto, padding, categoría y la llamada a la acción. Si alguno no navega, tienes una zona muerta.
- Tabula. Una parada por tarjeta (o dos con motivo) y foco visible sobre cada una.
- Revisa el HTML. Que no haya
<button>,<a>ni elementos contabindexdentro de un enlace envolvente.

En una revisión técnica completa, las plantillas de cards se incluyen en el análisis del enlazado interno y de la arquitectura. Si tu web tiene listados de categorías de ecommerce con cientos de tarjetas, ese análisis encaja con un trabajo de arquitectura web, porque el patrón de enlace de la card determina cuántos enlaces y con qué texto recibe cada URL.
Preguntas frecuentes
¿Puedo envolver toda la tarjeta en un enlace?
Es HTML válido si dentro no hay contenido interactivo (botones, otros enlaces o elementos con tabindex). El inconveniente es práctico: el nombre del enlace pasa a ser todo el contenido de la tarjeta. En mi prueba, 81 caracteres frente a 13. Si necesitas un enlace secundario, el envolvente deja de servirte.
¿Entiende Google mejor el enlace en el título que el enlace envolvente?
No está documentado. Google dice que usa el texto del enlace y que conviene que sea descriptivo, pero no explica cómo trata un ancla con varios elementos dentro. Que el título sea el ancla es una buena práctica por claridad, no una regla que Google haya publicado.
¿Qué hago con la imagen de la card?
Si el título ya es el enlace principal, alt="". Si la imagen es el único elemento enlazado, su alt es el ancla y tiene que describir el destino. Evita tener dos enlaces al mismo sitio, uno en la imagen y otro en el título.
¿Qué pasa si la tarjeta tiene un botón de favorito o de añadir al carrito?
Ese botón no puede ir dentro de un <a>. Con el stretched link se maqueta fuera del enlace, con position: relative y un z-index superior al de la capa estirada. Es el mismo ajuste que hice con el enlace secundario del autor.
¿Es mejor aria-label o texto oculto para los «Leer más»?
Lo mejor es no tener un «Leer más» enlazado y poner el enlace en el título. Si es inevitable, el texto oculto mantiene el nombre accesible alineado con lo que se ve. aria-label sustituye al texto visible y puede acabar diciendo algo distinto de lo que muestra la pantalla.
¿Funciona el stretched link en móvil?
Es CSS puro, así que el área clicable es la misma en cualquier dispositivo. En mi laboratorio solo probé con ratón en Chromium. No lo he verificado en pantallas táctiles reales ni en Safari.
¿Puedo seleccionar texto en una tarjeta con stretched link?
No arrastrando sobre ella: en mi prueba, la selección fue de 0 caracteres. Si tu contenido se copia a menudo, usa el patrón con JavaScript o limita el estirado a la imagen y el título.
Referencias y fuentes
Documentación consultada para este artículo.
- Hacer que tus enlaces se puedan rastrear Google Search Central
- The a element HTML Standard · WHATWG
- Understanding SC 2.4.4: Link Purpose (In Context) W3C WAI
- Understanding SC 2.5.8: Target Size (Minimum) W3C WAI
- <a>: the Anchor element MDN Web Docs
- Cards Inclusive Components · Heydon Pickering
- Stretched link Bootstrap 5.3
- Clickable card patterns and anti-patterns DEV Community
- Enlazar card-box sin sacrificar el anchor text Ahrefs Blog




