content-cards
intermediate
cards
animations
hover
transitions
components
ui
Categoría · Tarjetas de Contenido Nivel de Dificultad · Intermedio Publicado el · 15 de enero de 2024

Componentes de Tarjetas Animadas

Una colección de componentes de tarjetas modernas y animadas con efectos hover, transiciones e interacciones para aplicaciones web

#cards #animations #hover #transitions #components #ui

Diseño Responsivo

Soporte para Modo Oscuro

No

líneas

257

Compatibilidad del Navegador

No

Vista Previa en Vivo

Interactúa con el componente sin salir de la página.

500px

Componentes de Tarjetas Animadas

Una colección completa de componentes de tarjetas modernas y animadas con efectos hover suaves, transiciones elegantes y elementos interactivos perfectos para mostrar contenido, productos o servicios.

Características

  • Múltiples Estilos de Tarjetas: Tarjetas de productos, perfiles, blogs y características
  • Animaciones Suaves: Transiciones y efectos hover con CSS
  • Elementos Interactivos: Botones, insignias y áreas clicables
  • Diseño Responsivo: Se adapta a todos los tamaños de pantalla
  • Personalizable: Fácil modificación de colores, tamaños y animaciones
  • Accesibilidad: Navegación por teclado y soporte para lectores de pantalla
  • Optimizado para Rendimiento: Animaciones aceleradas por hardware
  • Diseño Moderno: Estética limpia y contemporánea

Demostración

<div class="cards-container">
  
  <div class="card product-card">
    <div class="card-image">
      <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=400" alt="Producto">
      <div class="card-badge">Nuevo</div>
      <div class="card-overlay">
        <button class="quick-view-btn">Vista Rápida</button>
      </div>
    </div>
    <div class="card-content">
      <div class="card-category">Zapatillas</div>
      <h3 class="card-title">Nike Air Max 270</h3>
      <p class="card-description">Zapatillas cómodas y elegantes perfectas para el uso diario.</p>
      <div class="card-price">
        <span class="current-price">€119.99</span>
        <span class="original-price">€149.99</span>
      </div>
      <div class="card-actions">
        <button class="btn-primary">Añadir al Carrito</button>
        <button class="btn-secondary" aria-label="Añadir a favoritos">
          <svg viewBox="0 0 24 24" fill="currentColor">
            <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
          </svg>
        </button>
      </div>
    </div>
  </div>

  
  <div class="card profile-card">
    <div class="card-header">
      <div class="profile-image">
        <img src="https://images.unsplash.com/photo-1494790108755-2616b612b786?w=150" alt="Perfil">
        <div class="status-indicator online"></div>
      </div>
      <div class="profile-info">
        <h3 class="profile-name">Sarah Johnson</h3>
        <p class="profile-role">Diseñadora UI/UX</p>
        <div class="profile-stats">
          <div class="stat">
            <span class="stat-number">127</span>
            <span class="stat-label">Proyectos</span>
          </div>
          <div class="stat">
            <span class="stat-number">2.4k</span>
            <span class="stat-label">Seguidores</span>
          </div>
        </div>
      </div>
    </div>
    <div class="card-content">
      <p class="profile-bio">Diseñadora apasionada creando experiencias de usuario hermosas y funcionales. Me encanta trabajar con tecnologías modernas.</p>
      <div class="skills">
        <span class="skill-tag">Figma</span>
        <span class="skill-tag">Sketch</span>
        <span class="skill-tag">Prototipado</span>
      </div>
    </div>
    <div class="card-actions">
      <button class="btn-primary">Seguir</button>
      <button class="btn-secondary">Mensaje</button>
    </div>
  </div>

  
  <div class="card blog-card">
    <div class="card-image">
      <img src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?w=400" alt="Artículo del blog">
      <div class="read-time">5 min lectura</div>
    </div>
    <div class="card-content">
      <div class="card-meta">
        <span class="category">Tecnología</span>
        <span class="date">15 Ene, 2024</span>
      </div>
      <h3 class="card-title">El Futuro del Desarrollo Web</h3>
      <p class="card-excerpt">Explorando las últimas tendencias y tecnologías que están dando forma al futuro del desarrollo web...</p>
      <div class="author">
        <img src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=40" alt="Autor" class="author-avatar">
        <div class="author-info">
          <span class="author-name">Juan Pérez</span>
          <span class="author-title">Desarrollador Senior</span>
        </div>
      </div>
    </div>
    <div class="card-footer">
      <div class="engagement">
        <button class="engagement-btn">
          <svg viewBox="0 0 24 24" fill="currentColor">
            <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
          </svg>
          <span>24</span>
        </button>
        <button class="engagement-btn">
          <svg viewBox="0 0 24 24" fill="currentColor">
            <path d="M21 6h-2l-1-2H6L5 6H3c-.55 0-1 .45-1 1s.45 1 1 1h1l1.5 9c.08.46.46.8.93.8h9.14c.47 0 .85-.34.93-.8L17 8h1c.55 0 1-.45 1-1s-.45-1-1-1z"/>
          </svg>
          <span>8</span>
        </button>
      </div>
      <button class="read-more-btn">Leer Más</button>
    </div>
  </div>

  
  <div class="card feature-card">
    <div class="feature-icon">
      <svg viewBox="0 0 24 24" fill="currentColor">
        <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
      </svg>
    </div>
    <div class="card-content">
      <h3 class="card-title">Características Premium</h3>
      <p class="card-description">Desbloquea funcionalidades avanzadas con nuestro plan premium incluyendo soporte prioritario y características exclusivas.</p>
      <ul class="feature-list">
        <li>Análisis Avanzados</li>
        <li>Soporte Prioritario</li>
        <li>Integraciones Personalizadas</li>
        <li>Colaboración en Equipo</li>
      </ul>
    </div>
    <div class="card-actions">
      <button class="btn-primary">Actualizar Ahora</button>
      <a href="#" class="learn-more">Saber Más</a>
    </div>
  </div>
</div>
.cards-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 2rem;
  padding: 2rem;
  max-width: 1400px;
  margin: 0 auto;
}.card {
  background: white;
  border-radius: 16px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
  overflow: hidden;
  transition: all 0.3s ease;
  position: relative;
  cursor: pointer;
}

.card:hover {
  transform: translateY(-8px);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}

.card-content {
  padding: 1.5rem;
}

.card-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: #1a1a1a;
  margin: 0 0 0.5rem 0;
  line-height: 1.3;
}

.card-description,
.card-excerpt {
  color: #6b7280;
  line-height: 1.6;
  margin: 0 0 1rem 0;
}.product-card {
  max-width: 350px;
}

.product-card .card-image {
  position: relative;
  overflow: hidden;
  height: 250px;
}

.product-card .card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.product-card:hover .card-image img {
  transform: scale(1.1);
}

.card-badge {
  position: absolute;
  top: 1rem;
  left: 1rem;
  background: #ef4444;
  color: white;
  padding: 0.25rem 0.75rem;
  border-radius: 20px;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.card-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.product-card:hover .card-overlay {
  opacity: 1;
}

.quick-view-btn {
  background: white;
  color: #1a1a1a;
  border: none;
  padding: 0.75rem 1.5rem;
  border-radius: 25px;
  font-weight: 600;
  cursor: pointer;
  transform: translateY(20px);
  transition: all 0.3s ease;
}

.product-card:hover .quick-view-btn {
  transform: translateY(0);
}

.card-category {
  color: #3b82f6;
  font-size: 0.875rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 0.5rem;
}

.card-price {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 1rem 0;
}

.current-price {
  font-size: 1.5rem;
  font-weight: 700;
  color: #1a1a1a;
}

.original-price {
  font-size: 1rem;
  color: #9ca3af;
  text-decoration: line-through;
}

.card-actions {
  display: flex;
  gap: 0.75rem;
  align-items: center;
}

.btn-primary {
  flex: 1;
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  color: white;
  border: none;
  padding: 0.75rem 1rem;
  border-radius: 8px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(59, 130, 246, 0.3);
}

.btn-secondary {
  width: 44px;
  height: 44px;
  background: #f3f4f6;
  border: none;
  border-radius: 8px;
  color: #6b7280;
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.btn-secondary:hover {
  background: #e5e7eb;
  color: #ef4444;
}

.btn-secondary svg {
  width: 20px;
  height: 20px;
}.profile-card {
  max-width: 350px;
  text-align: center;
}

.card-header {
  padding: 2rem 1.5rem 1rem;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  position: relative;
}

.profile-image {
  position: relative;
  display: inline-block;
  margin-bottom: 1rem;
}

.profile-image img {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  border: 4px solid white;
  object-fit: cover;
}

.status-indicator {
  position: absolute;
  bottom: 5px;
  right: 5px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid white;
}

.status-indicator.online {
  background: #10b981;
}

.profile-name {
  font-size: 1.5rem;
  font-weight: 700;
  margin: 0 0 0.25rem 0;
  color: white;
}

.profile-role {
  color: rgba(255, 255, 255, 0.8);
  margin: 0 0 1rem 0;
}

.profile-stats {
  display: flex;
  justify-content: center;
  gap: 2rem;
}

.stat {
  text-align: center;
}

.stat-number {
  display: block;
  font-size: 1.25rem;
  font-weight: 700;
  color: white;
}

.stat-label {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.7);
}

.profile-bio {
  text-align: left;
  margin-bottom: 1rem;
}

.skills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.skill-tag {
  background: #f3f4f6;
  color: #4b5563;
  padding: 0.25rem 0.75rem;
  border-radius: 20px;
  font-size: 0.75rem;
  font-weight: 500;
}.blog-card {
  max-width: 400px;
}

.blog-card .card-image {
  position: relative;
  height: 200px;
  overflow: hidden;
}

.blog-card .card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.blog-card:hover .card-image img {
  transform: scale(1.05);
}

.read-time {
  position: absolute;
  top: 1rem;
  right: 1rem;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 0.25rem 0.75rem;
  border-radius: 20px;
  font-size: 0.75rem;
  font-weight: 500;
}

.card-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.75rem;
  font-size: 0.875rem;
}

.category {
  color: #3b82f6;
  font-weight: 500;
}

.date {
  color: #9ca3af;
}

.author {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1rem;
}

.author-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
}

.author-info {
  display: flex;
  flex-direction: column;
}

.author-name {
  font-weight: 600;
  color: #1a1a1a;
  font-size: 0.875rem;
}

.author-title {
  color: #6b7280;
  font-size: 0.75rem;
}

.card-footer {
  padding: 1rem 1.5rem;
  border-top: 1px solid #f3f4f6;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.engagement {
  display: flex;
  gap: 1rem;
}

.engagement-btn {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  background: none;
  border: none;
  color: #6b7280;
  cursor: pointer;
  transition: color 0.3s ease;
  font-size: 0.875rem;
}

.engagement-btn:hover {
  color: #3b82f6;
}

.engagement-btn svg {
  width: 16px;
  height: 16px;
}

.read-more-btn {
  background: none;
  border: none;
  color: #3b82f6;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.3s ease;
}

.read-more-btn:hover {
  color: #1d4ed8;
}.feature-card {
  max-width: 350px;
  text-align: center;
  border: 2px solid #f3f4f6;
  transition: all 0.3s ease;
}

.feature-card:hover {
  border-color: #3b82f6;
  transform: translateY(-8px);
}

.feature-icon {
  width: 80px;
  height: 80px;
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 2rem auto 1.5rem;
  transition: transform 0.3s ease;
}

.feature-card:hover .feature-icon {
  transform: scale(1.1);
}

.feature-icon svg {
  width: 40px;
  height: 40px;
  color: white;
}

.feature-list {
  list-style: none;
  padding: 0;
  margin: 1.5rem 0;
  text-align: left;
}

.feature-list li {
  padding: 0.5rem 0;
  color: #4b5563;
  position: relative;
  padding-left: 1.5rem;
}

.feature-list li::before {
  content: '✓';
  position: absolute;
  left: 0;
  color: #10b981;
  font-weight: bold;
}

.learn-more {
  color: #6b7280;
  text-decoration: none;
  font-weight: 500;
  transition: color 0.3s ease;
}

.learn-more:hover {
  color: #3b82f6;
}.dark .card {
  background: #1f2937;
  border: 1px solid #374151;
}

.dark .card-title {
  color: white;
}

.dark .card-description,
.dark .card-excerpt {
  color: #d1d5db;
}

.dark .btn-secondary {
  background: #374151;
  color: #d1d5db;
}

.dark .btn-secondary:hover {
  background: #4b5563;
}

.dark .skill-tag {
  background: #374151;
  color: #d1d5db;
}

.dark .card-footer {
  border-top-color: #374151;
}

.dark .feature-card {
  border-color: #374151;
}

.dark .feature-card:hover {
  border-color: #3b82f6;
}@media (max-width: 768px) {
  .cards-container {
    grid-template-columns: 1fr;
    padding: 1rem;
    gap: 1.5rem;
  }
  
  .card {
    max-width: none;
  }
  
  .profile-stats {
    gap: 1rem;
  }
  
  .card-actions {
    flex-direction: column;
  }
  
  .btn-secondary {
    width: 100%;
    height: 44px;
  }
}

@media (max-width: 480px) {
  .card-content {
    padding: 1rem;
  }
  
  .card-header {
    padding: 1.5rem 1rem 1rem;
  }
  
  .card-title {
    font-size: 1.125rem;
  }
}@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
}

.card {
  animation: fadeInUp 0.6s ease;
}

.feature-icon:hover {
  animation: pulse 1s infinite;
}
class TarjetasAnimadas {
  constructor(selector) {
    this.container = document.querySelector(selector);
    this.cards = this.container.querySelectorAll('.card');
    this.observerOptions = {
      threshold: 0.1,
      rootMargin: '0px 0px -50px 0px'
    };
    
    this.init();
  }

  init() {
    this.setupIntersectionObserver();
    this.setupEventListeners();
    this.setupLazyLoading();
    this.setupAccessibility();
  }

  setupIntersectionObserver() {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          entry.target.classList.add('animate-in');
          observer.unobserve(entry.target);
        }
      });
    }, this.observerOptions);

    this.cards.forEach(card => {
      observer.observe(card);
    });
  }

  setupEventListeners() {
    this.cards.forEach(card => {

      const addToCartBtn = card.querySelector('.btn-primary');
      if (addToCartBtn && card.classList.contains('product-card')) {
        addToCartBtn.addEventListener('click', (e) => {
          e.stopPropagation();
          this.handleAddToCart(card);
        });
      }

      const wishlistBtn = card.querySelector('.btn-secondary');
      if (wishlistBtn && card.classList.contains('product-card')) {
        wishlistBtn.addEventListener('click', (e) => {
          e.stopPropagation();
          this.handleWishlist(card, wishlistBtn);
        });
      }

      const followBtn = card.querySelector('.btn-primary');
      if (followBtn && card.classList.contains('profile-card')) {
        followBtn.addEventListener('click', (e) => {
          e.stopPropagation();
          this.handleFollow(card, followBtn);
        });
      }

      const readMoreBtn = card.querySelector('.read-more-btn');
      if (readMoreBtn) {
        readMoreBtn.addEventListener('click', (e) => {
          e.stopPropagation();
          this.handleReadMore(card);
        });
      }

      const engagementBtns = card.querySelectorAll('.engagement-btn');
      engagementBtns.forEach(btn => {
        btn.addEventListener('click', (e) => {
          e.stopPropagation();
          this.handleEngagement(btn);
        });
      });

      card.addEventListener('click', () => {
        this.handleCardClick(card);
      });

      card.addEventListener('keydown', (e) => {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          this.handleCardClick(card);
        }
      });
    });
  }

  setupLazyLoading() {
    const images = this.container.querySelectorAll('img[data-src]');
    const imageObserver = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          img.src = img.dataset.src;
          img.classList.remove('lazy');
          imageObserver.unobserve(img);
        }
      });
    });

    images.forEach(img => {
      imageObserver.observe(img);
    });
  }

  setupAccessibility() {
    this.cards.forEach((card, index) => {

      card.setAttribute('tabindex', '0');
      card.setAttribute('role', 'article');

      const title = card.querySelector('.card-title')?.textContent;
      if (title) {
        card.setAttribute('aria-label', `Tarjeta: ${title}`);
      }
    });
  }

  handleAddToCart(card) {
    const btn = card.querySelector('.btn-primary');
    const originalText = btn.textContent;

    btn.textContent = '¡Añadido!';
    btn.style.background = '#10b981';

    const productTitle = card.querySelector('.card-title').textContent;
    window.dispatchEvent(new CustomEvent('addToCart', {
      detail: { product: productTitle, card }
    }));

    setTimeout(() => {
      btn.textContent = originalText;
      btn.style.background = '';
    }, 2000);
  }

  handleWishlist(card, btn) {
    const isActive = btn.classList.contains('active');
    
    if (isActive) {
      btn.classList.remove('active');
      btn.style.color = '';
    } else {
      btn.classList.add('active');
      btn.style.color = '#ef4444';
    }

    const productTitle = card.querySelector('.card-title').textContent;
    window.dispatchEvent(new CustomEvent('toggleWishlist', {
      detail: { product: productTitle, added: !isActive }
    }));
  }

  handleFollow(card, btn) {
    const isFollowing = btn.classList.contains('following');
    
    if (isFollowing) {
      btn.textContent = 'Seguir';
      btn.classList.remove('following');
    } else {
      btn.textContent = 'Siguiendo';
      btn.classList.add('following');
    }

    const profileName = card.querySelector('.profile-name').textContent;
    window.dispatchEvent(new CustomEvent('toggleFollow', {
      detail: { profile: profileName, following: !isFollowing }
    }));
  }

  handleReadMore(card) {

    const title = card.querySelector('.card-title').textContent;
    window.dispatchEvent(new CustomEvent('readMore', {
      detail: { title, card }
    }));
  }

  handleEngagement(btn) {
    const countSpan = btn.querySelector('span');
    if (countSpan) {
      const currentCount = parseInt(countSpan.textContent);
      const isActive = btn.classList.contains('active');
      
      if (isActive) {
        countSpan.textContent = currentCount - 1;
        btn.classList.remove('active');
      } else {
        countSpan.textContent = currentCount + 1;
        btn.classList.add('active');

        btn.style.transform = 'scale(1.2)';
        setTimeout(() => {
          btn.style.transform = '';
        }, 200);
      }
    }
  }

  handleCardClick(card) {

    card.style.transform = 'scale(0.98)';
    setTimeout(() => {
      card.style.transform = '';
    }, 150);

    const title = card.querySelector('.card-title')?.textContent;
    window.dispatchEvent(new CustomEvent('cardClick', {
      detail: { title, card }
    }));
  }

  addCard(cardHTML, position = 'end') {
    const tempDiv = document.createElement('div');
    tempDiv.innerHTML = cardHTML;
    const newCard = tempDiv.firstElementChild;
    
    if (position === 'start') {
      this.container.insertBefore(newCard, this.container.firstChild);
    } else {
      this.container.appendChild(newCard);
    }

    this.setupEventListeners();

    newCard.style.opacity = '0';
    newCard.style.transform = 'translateY(30px)';
    setTimeout(() => {
      newCard.style.transition = 'all 0.3s ease';
      newCard.style.opacity = '1';
      newCard.style.transform = 'translateY(0)';
    }, 100);
  }

  removeCard(cardElement) {
    cardElement.style.transition = 'all 0.3s ease';
    cardElement.style.opacity = '0';
    cardElement.style.transform = 'translateY(-30px)';
    
    setTimeout(() => {
      cardElement.remove();
    }, 300);
  }

  filterCards(filterFn) {
    this.cards.forEach(card => {
      const shouldShow = filterFn(card);
      card.style.display = shouldShow ? 'block' : 'none';
    });
  }

  sortCards(sortFn) {
    const cardsArray = Array.from(this.cards);
    cardsArray.sort(sortFn);
    
    cardsArray.forEach(card => {
      this.container.appendChild(card);
    });
  }

  destroy() {

    this.cards.forEach(card => {
      card.removeEventListener('click', this.handleCardClick);
      card.removeEventListener('keydown', this.handleKeydown);
    });
  }
}

document.addEventListener('DOMContentLoaded', () => {
  const cardsContainer = document.querySelector('.cards-container');
  if (cardsContainer) {
    const tarjetasAnimadas = new TarjetasAnimadas('.cards-container');

    window.tarjetasAnimadas = tarjetasAnimadas;

    window.addEventListener('addToCart', (e) => {
      console.log('Producto añadido al carrito:', e.detail.product);
    });
    
    window.addEventListener('toggleWishlist', (e) => {
      console.log('Lista de deseos modificada:', e.detail);
    });
    
    window.addEventListener('toggleFollow', (e) => {
      console.log('Seguimiento modificado:', e.detail);
    });
    
    window.addEventListener('cardClick', (e) => {
      console.log('Tarjeta clicada:', e.detail.title);
    });
  }
});

Ejemplos de Uso

Implementación Básica


const cards = new TarjetasAnimadas('.cards-container');

window.addEventListener('addToCart', (e) => {

  console.log('Añadido al carrito:', e.detail.product);
});

Gestión Dinámica de Tarjetas


const newCardHTML = `
  <div class="card product-card">
    
  </div>
`;
cards.addCard(newCardHTML);

cards.filterCards(card => {
  return card.classList.contains('product-card');
});

cards.sortCards((a, b) => {
  const priceA = parseFloat(a.querySelector('.current-price').textContent.replace('€', ''));
  const priceB = parseFloat(b.querySelector('.current-price').textContent.replace('€', ''));
  return priceA - priceB;
});

Estilización Personalizada

.card.custom-theme {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
}

.card.custom-theme .card-title {
  color: white;
}

.card.custom-theme .card-description {
  color: rgba(255, 255, 255, 0.8);
}

Métodos de API

MétodoDescripciónParámetros
addCard(html, position)Añadir nueva tarjeta al contenedorhtml: HTML de la tarjeta, position: ‘start’ o ‘end’
removeCard(element)Remover tarjeta con animaciónelement: Elemento DOM de la tarjeta
filterCards(filterFn)Filtrar tarjetas visiblesfilterFn: Función que retorna boolean
sortCards(sortFn)Ordenar tarjetas en el contenedorsortFn: Función de comparación
destroy()Limpiar event listeners-

Opciones de Personalización

Variables CSS

:root {
  --card-bg: white;
  --card-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
  --card-hover-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
  --card-border-radius: 16px;
  --card-padding: 1.5rem;
  --primary-color: #3b82f6;
  --text-color: #1a1a1a;
  --text-secondary: #6b7280;
}

Configuración de Animaciones

.card {
  --hover-transform: translateY(-8px);
  --hover-duration: 0.3s;
  --hover-easing: ease;
}

Características de Accesibilidad

  • Navegación por Teclado: Soporte completo con Tab y Enter
  • Soporte para Lectores de Pantalla: Etiquetas ARIA y roles apropiados
  • Gestión de Foco: Indicadores de foco claros
  • Contraste de Color: Cumple con WCAG 2.1 AA
  • HTML Semántico: Jerarquía de encabezados y estructura apropiada

Soporte de Navegadores

  • Chrome 60+
  • Firefox 55+
  • Safari 12+
  • Edge 79+
  • iOS Safari 12+
  • Android Chrome 60+

Consideraciones de Rendimiento

  • Aceleración por Hardware: Transformaciones CSS para animaciones suaves
  • Intersection Observer: Animaciones eficientes basadas en scroll
  • Carga Perezosa: Imágenes cargadas solo cuando es necesario
  • Delegación de Eventos: Manejo optimizado de eventos
  • Reflows Mínimos: Animaciones solo con CSS donde es posible

Ejemplo de Integración

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Demo de Tarjetas Animadas</title>
  <link rel="stylesheet" href="cards.css">
</head>
<body>
  <div class="cards-container">
    
  </div>
  
  <script src="cards.js"></script>
  <script>

    document.addEventListener('DOMContentLoaded', () => {
      const cards = new TarjetasAnimadas('.cards-container');

      window.addEventListener('addToCart', (e) => {

        mostrarNotificacion(`¡${e.detail.product} añadido al carrito!`);
      });
    });
  </script>
</body>
</html>

HTML

47

líneas

CSS

210

líneas


                <div class="cards-container">
  <div class="card card-hover">
    <div class="card-image">
      <img src="https://via.placeholder.com/300x200" alt="Imagen de ejemplo">
      <div class="card-overlay">
        <button class="btn-action">Ver más</button>
      </div>
    </div>
    <div class="card-content">
      <h3>Tarjeta Animada</h3>
      <p>Esta es una tarjeta con efectos hover suaves y transiciones elegantes.</p>
      <div class="card-footer">
        <span class="card-date">15 Ene 2024</span>
        <span class="card-category">Diseño</span>
      </div>
    </div>
  </div>
  
  <div class="card card-flip">
    <div class="card-inner">
      <div class="card-front">
        <h3>Tarjeta con Flip</h3>
        <p>Pasa el cursor para ver el reverso</p>
      </div>
      <div class="card-back">
        <h3>Información adicional</h3>
        <p>Contenido del reverso de la tarjeta con más detalles.</p>
        <button class="btn-secondary">Acción</button>
      </div>
    </div>
  </div>
  
  <div class="card card-scale">
    <div class="card-header">
      <div class="card-icon">🎨</div>
      <h3>Tarjeta con Escala</h3>
    </div>
    <div class="card-body">
      <p>Efecto de escala al hacer hover con animación suave.</p>
      <ul class="card-features">
        <li>Animación fluida</li>
        <li>Diseño moderno</li>
        <li>Fácil personalización</li>
      </ul>
    </div>
  </div>
</div>

              
47líneas
1425caracteres
HTMLIdioma

Fragmentos de Código Relacionados

Explora packs de plantillas

¿Necesitas bloques más grandes? Descubre landings y colecciones de componentes.

Abrir la biblioteca de plantillas ->