DEV Community

Cover image for Diseño e Implementación de Cards en Desarrollo Web Moderno
Joaquín Gutiérrez
Joaquín Gutiérrez

Posted on

Diseño e Implementación de Cards en Desarrollo Web Moderno

Las cards (tarjetas) son uno de los componentes más versátiles en el diseño web moderno. Se utilizan para presentar información de manera concisa y visualmente atractiva, desde productos en tiendas online hasta artículos en blogs. En esta guía, exploraremos diferentes implementaciones y mejores prácticas.

Anatomía de una Card

Una card típica consta de varios elementos:

<div class="card">
  <!-- Imagen -->
  <img src="imagen.jpg" alt="Descripción" class="card-image">

  <!-- Contenido -->
  <div class="card-content">
    <h2 class="card-title">Título de la Card</h2>
    <p class="card-description">Descripción o contenido principal</p>

    <!-- Pie de Card -->
    <div class="card-footer">
      <button class="card-button">Acción Principal</button>
      <span class="card-meta">Info adicional</span>
    </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Implementaciones

1. Card Básica con CSS

.card {
  width: 300px;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: transform 0.2s ease;
}

.card:hover {
  transform: translateY(-4px);
}

.card-image {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.card-content {
  padding: 16px;
}

.card-title {
  margin: 0 0 8px;
  font-size: 1.25rem;
}

.card-description {
  color: #666;
  line-height: 1.5;
}

.card-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 16px;
  margin-top: 16px;
  border-top: 1px solid #eee;
}
Enter fullscreen mode Exit fullscreen mode

2. Card con Tailwind CSS

<div class="max-w-sm rounded overflow-hidden shadow-lg hover:-translate-y-1 transition-transform">
  <img class="w-full h-48 object-cover" src="imagen.jpg" alt="Descripción">
  <div class="px-6 py-4">
    <h2 class="font-bold text-xl mb-2">Título de la Card</h2>
    <p class="text-gray-700 text-base">
      Descripción o contenido principal
    </p>
  </div>
  <div class="px-6 py-4 border-t border-gray-200">
    <button class="bg-blue-500 text-white px-4 py-2 rounded">
      Acción
    </button>
    <span class="text-gray-500 text-sm">Meta info</span>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

3. Componente React con TypeScript

interface CardProps {
  image: string;
  title: string;
  description: string;
  action?: () => void;
  meta?: string;
}

const Card: React.FC<CardProps> = ({
  image,
  title,
  description,
  action,
  meta
}) => {
  return (
    <div className="card">
      <img
        src={image}
        alt={title}
        className="card-image"
        loading="lazy"
      />
      <div className="card-content">
        <h2 className="card-title">{title}</h2>
        <p className="card-description">{description}</p>

        <div className="card-footer">
          {action && (
            <button
              onClick={action}
              className="card-button"
            >
              Ver más
            </button>
          )}
          {meta && <span className="card-meta">{meta}</span>}
        </div>
      </div>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

4. Componente Vue 3

<template>
  <div class="card">
    <img :src="image" :alt="title" class="card-image">
    <div class="card-content">
      <h2 class="card-title">{{ title }}</h2>
      <p class="card-description">{{ description }}</p>

      <div class="card-footer">
        <button
          v-if="action"
          @click="action"
          class="card-button"
        >
          Ver más
        </button>
        <span v-if="meta" class="card-meta">{{ meta }}</span>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
defineProps<{
  image: string;
  title: string;
  description: string;
  action?: () => void;
  meta?: string;
}>();
</script>
Enter fullscreen mode Exit fullscreen mode

Patrones de Diseño

1. Card Grid Responsiva

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 24px;
  padding: 24px;
}
Enter fullscreen mode Exit fullscreen mode

2. Cards con Aspect Ratio

.card-image-container {
  position: relative;
  padding-top: 56.25%; /* 16:9 Aspect Ratio */
}

.card-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
Enter fullscreen mode Exit fullscreen mode

3. Skeleton Loading

.card-skeleton {
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% { opacity: 0.6; }
  50% { opacity: 1; }
  100% { opacity: 0.6; }
}
Enter fullscreen mode Exit fullscreen mode

Accesibilidad

<div 
  class="card" 
  role="article"
  tabindex="0"
>
  <img 
    src="imagen.jpg" 
    alt="Descripción detallada"
    aria-describedby="card-desc"
  >
  <div class="card-content">
    <h2 id="card-title">Título</h2>
    <p id="card-desc">Descripción</p>
    <button 
      class="card-button"
      aria-labelledby="card-title"
    >
      Ver más
    </button>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Mejores Prácticas

  1. Optimización de Imágenes
import Image from 'next/image';

<Image
  src={imageUrl}
  alt={title}
  width={300}
  height={200}
  placeholder="blur"
  blurDataURL={thumbnailUrl}
/>
Enter fullscreen mode Exit fullscreen mode
  1. Manejo de Errores de Imagen
const handleImageError = (e: React.SyntheticEvent<HTMLImageElement>) => {
  e.currentTarget.src = '/placeholder.jpg';
};

<img
  src={imageUrl}
  onError={handleImageError}
  alt={title}
/>
Enter fullscreen mode Exit fullscreen mode
  1. Truncado de Texto
.card-title {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
Enter fullscreen mode Exit fullscreen mode

Animaciones

/* Hover Effects */
.card {
  transition: all 0.3s ease;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}

/* Click Effect */
.card:active {
  transform: translateY(-2px);
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
Enter fullscreen mode Exit fullscreen mode

Consideraciones de Rendimiento

  1. Lazy Loading
<img 
  loading="lazy"
  src="imagen.jpg"
  alt="Descripción"
>
Enter fullscreen mode Exit fullscreen mode
  1. Intersection Observer
useEffect(() => {
  const observer = new IntersectionObserver(
    (entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          // Cargar contenido
        }
      });
    },
    { threshold: 0.1 }
  );

  observer.observe(cardRef.current);
  return () => observer.disconnect();
}, []);
Enter fullscreen mode Exit fullscreen mode

Conclusión

Las cards son componentes fundamentales en el diseño web moderno. Una buena implementación debe considerar:

  • Diseño responsivo
  • Accesibilidad
  • Rendimiento
  • Experiencia de usuario
  • Mantenibilidad del código

Recursos Adicionales

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay