Introducción
Este tutorial muestra, paso a paso y con todo lujo de detalles, cómo crear tarjetas de post (card design) usando CSS Grid dentro del loop de WordPress. Encontrarás ejemplos concretos de código PHP para el loop, CSS para la cuadrícula y las tarjetas, buenas prácticas de accesibilidad y rendimiento, y variantes para distintos casos de uso (imagen destacada, excerpt, overlay, responsive, lazy-loading, etc.).
Requisitos y consideraciones previas
- Tema hijo o tema propio donde puedas editar archivos como index.php, archive.php o un template part (por ejemplo, template-parts/content-card.php).
- Conocimientos básicos de la estructura del loop de WordPress y cómo enqueuear estilos y scripts.
- Soporte para imagen destacada (add_theme_support(post-thumbnails)).
1. Estructura HTML/PHP básica del loop
La idea es generar un marcado semántico por cada post que se convierta en una tarjeta. Cada tarjeta será un article con un a que cubre la tarjeta (link clickable accesible), imagen y contenido (título, excerpt, meta opcional).
Ejemplo de loop (colócalo en archive.php, index.php o template-part):
lt!-- Contenedor de la grid --gt
ltdiv class=posts-gridgt
lt?php while ( have_posts() ) : the_post() ?gt
ltarticle id=post-lt?php the_ID() ?gt lt?php post_class(post-card) ?gtgt
lta class=post-card__link href=lt?php the_permalink() ?gt aria-labelledby=post-title-lt?php the_ID() ?gtgt
lt?php if ( has_post_thumbnail() ): ?gt
lt?php the_post_thumbnail(medium_large, array(
class =gt post-card__image,
alt =gt get_the_title(),
loading =gt lazy
)) ?gt
lt?php else: ?gt
ltimg class=post-card__image src=lt?php echo esc_url(get_template_directory_uri() . /assets/img/placeholder.jpg) ?gt alt=lt?php the_title_attribute() ?gt loading=lazygt
lt?php endif ?gt
ltdiv class=post-card__contentgt
lth3 id=post-title-lt?php the_ID() ?gt class=post-card__titlegtlt?php the_title() ?gtlt/h3gt
ltp class=post-card__excerptgtlt?php echo wp_trim_words( get_the_excerpt() ?: get_the_content(), 30, ... ) ?gtlt/pgt
lt/divgt
lt/agt
lt/articlegt
lt?php endwhile ?gt
lt/divgt
lt?php endif ?gt
Observaciones clave del marcado:
- El enlace .post-card__link envuelve toda la tarjeta para que el área sea clicable y accesible mediante teclado.
- Se usan funciones nativas: the_post_thumbnail, the_permalink, the_title, wp_trim_words.
- Añade loading=lazy para imágenes, o usa la API de imágenes responsive de WP con srcset/sizes si quieres optimizar más.
2. Enqueue del CSS
Añade tu archivo CSS en functions.php para asegurarte de que se cargue correctamente.
function theme_enqueue_styles() {
wp_enqueue_style( theme-cards, get_template_directory_uri() . /assets/css/cards.css, array(), 1.0 )
}
add_action( wp_enqueue_scripts, theme_enqueue_styles )
3. CSS Grid: diseño de la cuadrícula y tarjetas
A continuación tienes un CSS completo y comentado que implementa una grid responsiva, tarjetas con imagen, overlay sutil, foco accesible y un diseño que mantiene la consistencia entre filas.
:root{
--gap: clamp(1rem, 1.2vw, 1.5rem)
--card-radius: 12px
--card-bg: #fff
--card-shadow: 0 4px 18px rgba(16,24,40,0.06)
--accent: #0066ff
}
/ Contenedor grid /
.posts-grid{
display: grid
grid-template-columns: repeat( auto-fill, minmax(280px, 1fr) )
gap: var(--gap)
align-items: start / que las tarjetas comiencen arriba /
margin: 0
padding: 0
}
/ Tarjeta /
.post-card{
list-style: none
background: var(--card-bg)
border-radius: var(--card-radius)
box-shadow: var(--card-shadow)
overflow: hidden
transition: transform .22s ease, box-shadow .22s ease
display: block
}
/ Hacemos que el enlace ocupe toda la tarjeta /
.post-card__link{
color: inherit
text-decoration: none
display: flex
flex-direction: column
height: 100%
}
/ Imagen: usar aspect-ratio para mantener proporción /
.post-card__image{
width: 100%
height: auto
display: block
object-fit: cover
aspect-ratio: 16/9 / soporte moderno /
}
/ Contenido de la tarjeta: flex para empujar elementos al fondo si se desea /
.post-card__content{
padding: 1rem
display: flex
flex-direction: column
gap: .5rem
flex: 1 1 auto
}
/ Título y excerpt /
.post-card__title{
font-size: 1.05rem
margin: 0
line-height: 1.2
}
.post-card__excerpt{
margin: 0
color: #475569
font-size: .95rem
flex: 1 1 auto
}
/ Efectos hover / focus /
.post-card:focus-within,
.post-card:hover{
transform: translateY(-6px)
box-shadow: 0 10px 30px rgba(16,24,40,0.12)
}
/ Indicador de foco claro para teclado /
.post-card__link:focus{
outline: 3px solid rgba(0,102,255,0.15)
outline-offset: 3px
border-radius: var(--card-radius)
}
/ Overlay sutil sobre imagen al hover /
.post-card__image{
transition: transform .35s ease
}
.post-card:hover .post-card__image,
.post-card:focus-within .post-card__image{
transform: scale(1.03)
}
/ Responsive: aumentar columnas en pantallas grandes /
@media (min-width: 1200px){
.posts-grid{
grid-template-columns: repeat(4, 1fr)
}
}
@media (min-width: 900px) and (max-width:1199px){
.posts-grid{
grid-template-columns: repeat(3, 1fr)
}
}
@media (min-width: 600px) and (max-width:899px){
.posts-grid{
grid-template-columns: repeat(2, 1fr)
}
}
Explicación de decisiones CSS:
- grid-template-columns con auto-fill y minmax permite tarjetas fluidas y responsive sin breakpoints forzados.
- aspect-ratio en la imagen mantiene una proporción constante (16:9), evitando saltos visuales al cargar contenido.
- display:flex en el enlace y en .post-card__content asegura que los títulos/excerpt ocupen el espacio y las tarjetas tengan alturas similares cuando sea necesario.
- transform en hover añade dinamismo sin afectar el layout de la grid (no causa reflow costoso).
4. Imágenes responsive y lazy-loading
Para optimizar imágenes y servir tamaños correctos en cada viewport usa las funciones de WordPress que generan srcset y sizes. Ejemplo en el loop:
lt?php
// Dentro de tu loop
if ( has_post_thumbnail() ) {
// medium_large es un ejemplo WP generará srcset automáticamente
echo wp_get_attachment_image( get_post_thumbnail_id(), medium_large, false, array(
class =gt post-card__image,
loading =gt lazy,
alt =gt get_the_title()
) )
}
?gt
wp_get_attachment_image incluye srcset y sizes, lo que mejora la carga y usabilidad en móviles. Para un control más fino configura un atributo sizes acorde al ancho de la columna en la grid.
5. Variantes: overlay con título sobre la imagen
Si quieres un diseño donde el título aparezca sobre la imagen con un degradado para legibilidad, puedes usar este patrón:
.post-card__image-wrap{
position: relative
overflow: hidden
}
.post-card__image{
display: block
width: 100%
height: auto
aspect-ratio: 16/9
}
.post-card__overlay{
position: absolute
inset: auto 0 0 0 / pegado al bottom /
padding: .75rem
background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.5) 100%)
color: #fff
}
ltdiv class=post-card__image-wrapgt
ltimg class=post-card__image src=... alt=... /gt
ltdiv class=post-card__overlaygt
lth3 class=post-card__titlegtTítulo sobre imagenlt/h3gt
lt/divgt
lt/divgt
6. Tarjetas de altura uniforme
Si buscas que todas las tarjetas de una fila tengan la misma altura visual, dos opciones fiables:
- Usar display:flex dentro de cada tarjeta y que el contenido crezca con flex: 1 así el pie o botón queda alineado.
- Usar grid-auto-rows una técnica que calcule span (más avanzada y requiere JS si quieres grid masonry-like). En la gran mayoría de casos, la opción flex es suficiente y más simple.
7. Accesibilidad
- Asegura que todas las imágenes tengan atributo alt con un texto significativo usa the_title() o get_the_excerpt() si aplica.
- El enlace principal debe tener aria-labelledby apuntando al título para reforzar la relación en lectores de pantalla.
- Proporciona foco visible (.post-card__link:focus) para navegación con teclado.
- Evita que el excerpt sea demasiado largo usa wp_trim_words para limitarlo.
8. Rendimiento
- Sirve imágenes responsivas con srcset/sizes y genera thumbnails adecuados en functions.php.
- Usa loading=lazy para imágenes fuera de pantalla.
- Minifica y concatena CSS si procede y cachea los assets.
- Si la lista de posts es muy larga, implementa paginación o carga diferida (infinite scroll) con una consulta AJAX que devuelva tarjetas renderizadas.
9. Ejemplo de WP_Query personalizado (cards fuera del loop principal)
args = array(
post_type =gt post,
posts_per_page =gt 12,
orderby =gt date,
order =gt DESC,
)
query = new WP_Query( args )
if ( query-gthave_posts() ) :
?>
ltdiv class=posts-gridgt
lt?php while ( query-gthave_posts() ) : query-gtthe_post() ?gt
lt!-- Reutiliza el mismo marcado de la tarjeta aquí --gt
lt?php endwhile ?gt
lt/divgt
lt?php
wp_reset_postdata()
endif
10. Variaciones avanzadas y notas finales
- Si buscas un diseño tipo “masonry” con columnas asimétricas, CSS Grid en navegadores modernos ofrece masonry experimental, pero para producción es más seguro usar librerías como Masonry o Isotope o una solución CSS JS que calcule row spans.
- Prueba en varios navegadores y dispositivos. Revisa rendimiento con Lighthouse y las imágenes con herramientas como Squoosh para determinar formatos y compresiones adecuadas.
- Si tu tema usa blocks (Full Site Editing), puedes adaptar los estilos para el block query o crear un block dinámico que renderice las tarjetas con el mismo CSS.
Resumen final
Con CSS Grid y un marcado semántico dentro del loop, puedes construir tarjetas de post limpias, accesibles y responsive. Aplica optimizaciones de imágenes (srcset, loading), mantiene un enfoque modular (clases BEM o similar) y trabaja el diseño con variables CSS para facilitar ajustes. Los ejemplos incluidos son una base robusta que puedes extender con overlays, meta adicional (autor, fecha), botones o microinteracciones según el proyecto.
Leave a Reply