Tarjetas con CSS: misma altura y el botón siempre abajo

Una fila de tarjetas con CSS es uno de los componentes más comunes de la web, y tiene un problema clásico: si el texto de una es más largo, los botones quedan desalineados. La combinación de Grid para la fila y Flexbox dentro de cada tarjeta lo resuelve con una sola línea.

El código

<ul class="tarjetas">
  <li class="tarjeta">
    <img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-5.jpg" alt="" width="640" height="420">
    <h2>Raspberry Pi 5</h2>
    <p>La más potente de la familia, con PCIe.</p>
    <a class="boton" href="#">Ver ficha</a>
  </li>
  <li class="tarjeta">
    <img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-zero-2-w.jpg" alt="" width="640" height="420">
    <h2>Raspberry Pi Zero 2 W</h2>
    <p>Del tamaño de un chicle, con Wi-Fi y Bluetooth, para proyectos donde cada milímetro cuenta.</p>
    <a class="boton" href="#">Ver ficha</a>
  </li>
  <li class="tarjeta">
    <img src="https://decodigo.com/wp-content/uploads/2026/10/decodigo_placa_raspberry-pi-5.jpg" alt="" width="640" height="420">
    <h2>Raspberry Pi 4</h2>
    <p>La más vendida.</p>
    <a class="boton" href="#">Ver ficha</a>
  </li>
</ul>
.tarjetas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  padding: 0;
  list-style: none;
  font-family: system-ui, sans-serif;
}
.tarjeta {
  display: flex;
  flex-direction: column;
  background: white;
  border: 1px solid #e3e8ee;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 14px rgb(15 31 51 / 0.08);
}
.tarjeta img { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.tarjeta h2 { font-size: 1.1rem; margin: 12px 16px 4px; }
.tarjeta p { margin: 0 16px 12px; color: #33475b; }
.boton {
  margin: auto 16px 16px;   /* auto arriba: empuja el botón al fondo */
  align-self: flex-start;
  padding: 8px 14px;
  border-radius: 8px;
  background: #1e64af;
  color: white;
  text-decoration: none;
}

Las tres tarjetas miden lo mismo de alto y los tres botones terminan a la misma altura, aunque el texto de la segunda es mucho más largo (medido en los tres navegadores).

Las tres claves

  1. La misma altura viene gratis con Grid: las celdas de una misma fila se estiran a la altura de la más alta (align-items: stretch, el valor por omisión).
  2. Cada tarjeta es una columna flex (display: flex; flex-direction: column), así que su contenido se apila y el espacio sobrante queda disponible.
  3. margin-top: auto en el botón se come todo ese espacio sobrante y empuja el botón al fondo. Aquí va dentro de margin: auto 16px 16px. align-self: flex-start evita que el botón se estire a todo el ancho de la tarjeta.

La imagen usa aspect-ratio: 16 / 9 con object-fit: cover para que todas las fotos ocupen lo mismo aunque tengan proporciones distintas. Y la fila es una lista, como en la galería.

Si toda la tarjeta debe ser un enlace, no envuelvas todo en un <a> enorme (el lector de pantalla leería el texto entero como nombre del enlace). Deja el enlace en el título y haz que cubra la tarjeta con un ::after de position: absolute; inset: 0 sobre una tarjeta con position: relative.

Cada fragmento de HTML de esta página pasó por el Nu Html Checker 26.11.4 (el validador del W3C) y cada resultado se pintó y se midió en Chromium, Firefox y WebKit antes de publicarla. Prueba tus cambios en el editor de HTML y CSS o aprende desde cero con el curso.