The Shadow #1
The Shadow
Noir$12.99
Grid Workshop
Card de comic semántica y accesible: un <a> stretch-link cubre toda la card, con botones de favoritos y carrito que capturan su propio clic por encima del enlace.
The Shadow #1
$12.99
<a> con position:absolute; inset:0 cubre toda la card. El aria-label describe el destino; los lectores de pantalla lo anuncian sin ambigüedad.
z-index:2 (el link tiene z-index:1), por lo que capturan su propio clic sin propagarlo al enlace.
<article> es el contenedor; el link vive dentro como primer hijo absoluto. No se anidan <a> ni otro <article>.
aria-pressed comunica el estado a tecnologías asistivas.
<a class="card__link"> como primer hijo del <article>, seguido de portada, botones y cuerpo.
.card__link { position:absolute; inset:0; z-index:1; } y la card position:relative.
.card__fav, .card__cart { position:relative; z-index:2; } para que capturen su propio clic.
app.js, initCardFav() alterna aria-pressed y las clases icon-fill/icon-outline; initCardCart() agrega is-added por 2 s.
Snippets autocontenidos: copiá cada bloque y pegá en tu proyecto. Incluyen el CSS mínimo necesario con su propio :root.
<article class="card">
<a class="card__link" href="#detalle" aria-label="Ver detalle"></a>
<div class="card__cover">
<img src="portada.jpg" alt="Portada">
<span class="card__cover-title">The Shadow #1</span>
</div>
<button class="card__fav" aria-pressed="false" aria-label="Agregar a favoritos">
<svg viewBox="0 0 48 48"><path d="…" fill="currentColor"/></svg>
</button>
<div class="card__body">
<h2 class="card__title">The Shadow</h2>
<p class="card__meta">Guion: W. Gibson · Arte: A. Reyes</p>
<button class="card__cart" aria-label="Agregar al carrito">Agregar</button>
</div>
</article>
:root{
--surface:hsl(215,11%,3%);
--surface2:hsl(214,4%,5%);
--border:hsl(214,35%,22%);
--text:hsl(215,25%,85%);
--accent:hsl(22,100%,62%);
--danger:hsl(0,100%,71%);
}
.card{
position:relative;
width:230px;
background:var(--surface);
border:1px solid var(--border);
border-radius:0.625rem;
overflow:hidden;
}
.card__link{
position:absolute;
inset:0;
z-index:1;
}
.card__fav,
.card__cart{
position:relative;
z-index:2;
}
.card__fav[aria-pressed="true"]{
color:var(--danger);
border-color:var(--danger);
}
const fav = document.querySelector('.card__fav');
const cart = document.querySelector('.card__cart');
fav.addEventListener('click', () => {
const pressed = fav.getAttribute('aria-pressed') === 'true';
fav.setAttribute('aria-pressed', String(!pressed));
});
cart.addEventListener('click', () => {
if (cart.classList.contains('is-added')) return;
cart.classList.add('is-added');
setTimeout(() => cart.classList.remove('is-added'), 2000);
});