Crea un Carrusel de Testimonios Atractivo y Dinámico con HTML, CSS y JavaScript

Crea un Carrusel de Testimonios Atractivo y Dinámico con HTML, CSS y JavaScript

¿Quieres mostrar las opiniones de tus clientes de una forma visualmente impactante y profesional? Un carrusel de testimonios dinámico no solo capta la atención, sino que también genera confianza.

En este tutorial, te guiaré paso a paso para que construyas un carrusel de testimonios completamente funcional y adaptable a cualquier dispositivo. Usaremos HTML para la estructura, CSS para un diseño moderno con efecto de desenfoque (blur), y JavaScript para darle vida con animaciones, navegación y reproducción automática.

Lo mejor de todo es que está diseñado para que agregar nuevos testimonios en el futuro sea increíblemente sencillo, ¡sin necesidad de tocar el JavaScript!

La Estructura HTML

Primero, crearemos el esqueleto de nuestro carrusel. La estructura se divide en dos partes principales: el contenedor principal donde se muestra el testimonio activo y la zona de navegación con las imágenes en miniatura.

La clave aquí es cómo manejamos los datos. En lugar de escribirlos en el archivo JavaScript, los asignamos directamente a cada elemento de navegación usando atributos data-*. De esta forma, para añadir un nuevo testimonio, solo tienes que copiar y pegar un bloque <div class="nav-item"> y cambiar sus datos.

<div class="testimonial-carousel">
    <div class="testimonial-main-container">
        <img id="main-testimonial-image" src="" alt="Producto y testimonio" class="main-image">
        <div class="testimonial-box">
            <div class="testimonial-author">
                <img id="author-image" src="" alt="Foto del autor" class="testimonial-author-img">
                <div class="author-info">
                    <h3 id="author-name"></h3>
                    <p id="author-title"></p>
                </div>
            </div>
            <p id="testimonial-text"></p>
        </div>
        <div class="nav-arrow-container">
            <button class="nav-arrow arrow-left" aria-label="Anterior">
                <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M27 16H5" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                    <path d="M14 25V25C12.454 21.2639 9.59013 18.2255 5.95192 16.4615L5 16L6.41224 15.2297C9.77684 13.3944 12.4434 10.5023 14 7V7" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            </button>
            <button class="nav-arrow arrow-right" aria-label="Siguiente">
                <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M5 16H27" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                    <path d="M18 25V25C19.546 21.2639 22.4099 18.2255 26.0481 16.4615L27 16L25.5878 15.2297C22.2232 13.3944 19.5566 10.5023 18 7V7" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            </button>
        </div>
    </div>

    <div class="testimonial-nav-wrapper">
        <div class="nav-item" data-name="David R" data-title="Aficionado al crossfit" data-text="“Llevo años probando proteínas y esta es, sin duda, la más limpia y digestiva que he tomado. Se disuelve perfecto y no me da pesadez. El sabor Royal Cookies es brutal.”" data-main-image="AQUI COLOCA LA URL DE TU IMAGEN">
            <img src="AQUI COLOCA LA URL DE TU IMAGEN" alt="Testimonio de David R">
        </div>
        <div class="nav-item" data-name="Marta C" data-title="Powerlifter" data-text="“Excelente relación calidad-precio. Ideal para mis entrenos diarios sin romper el bolsillo. Me sorprendió lo bien que sabe y lo completo que es para ser concentrado.”" data-main-image="AQUI COLOCA LA URL DE TU IMAGEN">
            <img src="AQUI COLOCA LA URL DE TU IMAGEN" alt="Testimonio de Marta C">
        </div>
        <div class="nav-item" data-name="Zuri H." data-title="Culturista" data-text="“Por fin un gainer que no empalaga y no me revienta el estómago. Me ayuda a subir de peso limpio y con energía real. El sabor KicKac Choco es un vicio.”" data-main-image="AQUI COLOCA LA URL DE TU IMAGEN">
            <img src="AQUI COLOCA LA URL DE TU IMAGEN" alt="Testimonio de Zuri H">
        </div>
        </div>
</div>

Dando Estilo con CSS

Ahora, daremos vida al diseño. Este código se encarga de posicionar los elementos, crear el efecto de «cristal esmerilado» (backdrop-filter) en la caja de texto y asegurar que todo se vea bien tanto en ordenadores como en móviles (@media queries).

Puedes añadir este código en el personalizador de WordPress (Apariencia > Personalizar > CSS Adicional) o en la hoja de estilos de tu tema.

.testimonial-carousel {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 20px;
    width: 100%;
    position: relative;
    align-items: flex-start;
}

.testimonial-main-container {
    flex: 1;
    max-width: 60%;
    position: relative;
    border-radius: 20px;
    overflow: hidden;
}

.testimonial-main-container .main-image {
    width: 100%;
    height: 100%;
    max-width: 550px;
    max-height: 550px;
    object-fit: cover;
    display: block;
    border-radius: 20px;
    transition: opacity 0.5s ease-in-out;
}

.testimonial-box {
    position: absolute;
    bottom: 0;
    left: auto;
    right: 0;
    max-width: 400px;
    width: calc(100% - 60px);
    box-sizing: border-box;
    background-color: rgba(67, 67, 67, 0.6);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    padding: 30px;
    border-radius: 20px;
    box-shadow: 0 -5px 15px rgba(0, 0, 0, 0.3);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    color: white;
    transition: opacity 0.5s ease-in-out;
}

.testimonial-author {
    display: flex;
    align-items: center;
    margin-bottom: 15px;
    color: #fff;
}

.testimonial-author-img {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    margin-right: 15px;
    object-fit: cover;
    border: 2px solid #555;
    overflow: hidden;
}

.author-info h3 {
    margin: 0;
    font-size: 1.4em;
    font-weight: 400;
    color: #fff;
    font-family: 'Bebas Neue', sans-serif;
    line-height: 1em;
}

.author-info p {
    margin: 0;
    color: #aaa;
    font-size: 0.9em;
}

.testimonial-text {
    font-style: italic;
    color: #ddd;
    line-height: 1.5;
    font-size: 1.05em;
}

.testimonial-nav-wrapper {
    flex-shrink: 0;
    width: 40%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 10px;
    padding-top: 10px;
}

.nav-item {
    cursor: pointer;
    border-radius: 15px;
    overflow: hidden;
    border: 3px solid transparent;
    transition: border-color 0.3s ease, transform 0.2s ease;
    position: relative;
    aspect-ratio: 1 / 1;
    width: calc(49% - 10px);
    max-width: 100%;
}

.nav-item::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    transition: background-color 0.3s ease;
}

.nav-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.nav-item.active {
    display: none;
}

.nav-arrow-container {
    position: absolute;
    top: 20px;
    right: 20px;
    z-index: 11;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.nav-arrow {
    background: none;
    border: none;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    cursor: pointer;
    opacity: 0.8;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: opacity 0.3s ease;
}

.nav-arrow:hover,
.nav-arrow:active {
    background: none;
    opacity: 1;
}

.nav-arrow svg {
    width: 45px;
    height: 45px;
}

@media (max-width: 1024px) {
    .testimonial-main-container {
        max-width: 60%;
    }
    .testimonial-main-container .main-image {
        height: 420px;
        max-width: 100%;
        max-height: 480px;
    }
    .testimonial-box {
        max-width: 300px;
        padding: 15px;
        width: calc(100% - 30px);
    }
    .testimonial-text {
        line-height: 1.3;
        font-size: 1.0em;
    }
    .nav-arrow-container {
        top: 10px;
        right: 10px;
    }
}

@media (max-width: 767px) {
    .testimonial-carousel {
        flex-direction: column;
        align-items: center;
        gap: 20px;
    }
    .testimonial-main-container {
        max-width: 100%;
        width: 100%;
        height: auto;
    }
    .testimonial-main-container .main-image {
        height: 320px;
        max-height: 320px;
    }
    .testimonial-box {
        position: relative;
        bottom: auto;
        border-radius: 15px;
        margin-top: -80px;
        width: calc(100% - 40px);
        margin-left: 20px;
        margin-right: 20px;
        max-width: none;
    }
    .testimonial-nav-wrapper {
        width: 100%;
        justify-content: center;
    }
    .nav-item {
        width: 80px;
        height: 80px;
    }
    .nav-arrow-container {
        top: 10px;
        right: 10px;
        flex-direction: row;
    }
    .nav-arrow {
        width: 40px;
        height: 40px;
    }
}

La Magia del JavaScript

Finalmente, el código JavaScript que controla toda la lógica. Este script leerá los datos de los testimonios desde el HTML, manejará los clics en las flechas y miniaturas, y gestionará el carrusel automático que se pausa cuando el usuario interactúa con él.

Puedes añadir este código usando un plugin como «Code Snippets» o en un bloque HTML de Gutenberg, envuelto en etiquetas <script>.

document.addEventListener('DOMContentLoaded', function() {
    const carousel = document.querySelector('.testimonial-carousel');
    const mainImage = document.getElementById('main-testimonial-image');
    const testimonialBox = document.querySelector('.testimonial-box');
    const authorImage = document.getElementById('author-image');
    const authorName = document.getElementById('author-name');
    const authorTitle = document.getElementById('author-title');
    const testimonialText = document.getElementById('testimonial-text');
    const navItems = document.querySelectorAll('.nav-item');
    const arrowLeft = document.querySelector('.arrow-left');
    const arrowRight = document.querySelector('.arrow-right');

    let testimonials = [];
    navItems.forEach((item, index) => {
        testimonials.push({
            name: item.dataset.name,
            title: item.dataset.title,
            text: item.dataset.text,
            mainImage: item.dataset.mainImage,
            authorImage: item.querySelector('img').src,
            navElement: item
        });
        item.setAttribute('data-index', index);
    });

    let currentIndex = 0;
    let autoSlideInterval;

    function updateTestimonial(index) {
        currentIndex = (index + testimonials.length) % testimonials.length;
        const testimonial = testimonials[currentIndex];

        mainImage.style.opacity = '0';
        testimonialBox.style.opacity = '0';

        setTimeout(() => {
            mainImage.src = testimonial.mainImage;
            authorImage.src = testimonial.authorImage;
            authorName.textContent = testimonial.name;
            authorTitle.textContent = testimonial.title;
            testimonialText.textContent = testimonial.text;
            mainImage.style.opacity = '1';
            testimonialBox.style.opacity = '1';
        }, 300);

        navItems.forEach((item, idx) => {
            if (idx === currentIndex) {
                item.classList.add('active');
            } else {
                item.classList.remove('active');
            }
        });
    }

    function startAutoSlide() {
        stopAutoSlide();
        autoSlideInterval = setInterval(() => {
            updateTestimonial(currentIndex + 1);
        }, 5000);
    }

    function stopAutoSlide() {
        clearInterval(autoSlideInterval);
    }

    navItems.forEach(item => {
        item.addEventListener('click', function() {
            const index = parseInt(this.getAttribute('data-index'));
            updateTestimonial(index);
        });
    });

    arrowLeft.addEventListener('click', () => {
        updateTestimonial(currentIndex - 1);
    });

    arrowRight.addEventListener('click', () => {
        updateTestimonial(currentIndex + 1);
    });

    carousel.addEventListener('mouseenter', stopAutoSlide);
    carousel.addEventListener('mouseleave', startAutoSlide);

    [arrowLeft, arrowRight, ...navItems].forEach(element => {
        element.addEventListener('click', () => {
            stopAutoSlide();
            startAutoSlide();
        });
    });

    if (testimonials.length > 0) {
        updateTestimonial(0);
        startAutoSlide();
    }
});

¡Y listo! Con estos tres bloques de código, tendrás un carrusel de testimonios profesional, fácil de actualizar y que mejorará enormemente la apariencia de tu página web.