Come creare un effetto “Before & After” con due immagini (senza plugin) in WordPress

Vuoi mostrare ai visitatori il prima e dopo di una ristrutturazione, di un progetto grafico o di un restyling?

In questo tutorial ti spiego come creare un effetto Before / After interattivo utilizzando solo HTML, CSS e JavaScript, senza alcun plugin.

Funziona perfettamente anche su Brizy Cloud, Elementor, Divi o in un blocco HTML personalizzato di WordPress.

Clicca sulla linea e trascina il tuo mouse per scoprire l'immagine!

Trascina il tuo dito sulla linea per scoprire l'immagine!

Dopo i lavori Prima dei lavori
Prima Dopo

Cosa realizzeremo

Il risultato finale è un’immagine in formato 16:9 con una linea verticale centrale:

  • a sinistra, la foto del “prima”;
  • a destra, la foto del “dopo”;
  • con la possibilità di trascinare la linea per confrontare le due immagini.


L’effetto è fluido, reattivo e mobile-friend

Il codice completo

Incolla questo codice in un blocco HTML o blocco “Codice” di Brizy Cloud / Divi / WordPress:

Di seguito trovi il codice completo da copiare per creare un confronto tra due immagini, una “prima” e una “dopo”, con trascinamento della linea centrale. Funziona anche su dispositivi mobili.


<!-- ========================================================= -->
<!-- EFFETTO IMMAGINE PRIMA/DOPO con Oscillazione e Ritorno Automatico -->
<!-- ========================================================= -->
<div class="before-after-container">
    <img src="https://tuosito.com/path/dopo.jpg" alt="Dopo dei lavori" class="before-img">
    <img src="https://tuosito.com/path/prima.jpg" alt="Prima dei lavori" class="after-img">
    <div class="slider-handle"></div>
    <span class="label before">Prima</span>
    <span class="label after">Dopo</span>
</div>

<style>
.before-after-container {
  position: relative;
  width: 100%;
  max-width: 800px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  margin: 40px auto;
  user-select: none;
  touch-action: none;
}

.before-after-container img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

.after-img {
  clip-path: inset(0 50% 0 0);
  transition: none; /* Rimosso transition per lo script JS */
}

.slider-handle {
  position: absolute;
  top: 0;
  left: 50%;
  width: 3px;
  height: 100%;
  background: white;
  border: 1px solid rgba(0,0,0,0.3);
  box-shadow: 0 0 5px rgba(0,0,0,0.3);
  cursor: ew-resize;
  z-index: 10;
}

.label {
  position: absolute;
  top: 10px;
  padding: 4px 8px;
  background: rgba(0,0,0,0.6);
  color: white;
  font-size: 14px;
  border-radius: 4px;
  z-index: 20;
  transition: opacity 0.3s ease;
}

.label.before { left: 10px; }
.label.after { right: 10px; }

/* Le etichette scompaiono durante il trascinamento e l'oscillazione */
.before-after-container.dragging .label {
  opacity: 0;
}
</style>

<script>
document.addEventListener("DOMContentLoaded", () => {
  const container = document.querySelector('.before-after-container');
  if (!container) return;
  const afterImg = container.querySelector('.after-img');
  const handle = container.querySelector('.slider-handle');
  let isDragging = false;
  let isAutoMoving = true;

  // ? Parametri principali dell'oscillazione
  const centerPercent = 50;
  const amplitude = 7.5;
  const speed = 0.030;
    let theta = 0;

  function setPercent(percent) {
    const pct = Math.max(0, Math.min(100, percent));
    afterImg.style.clipPath = `inset(0 ${100 - pct}% 0 0)`;
    handle.style.left = pct + '%';
  }

  function percentFromClientX(clientX) {
    const rect = container.getBoundingClientRect();
    const x = clientX - rect.left;
    return (x / rect.width) * 100;
  }

  function stopAuto() {
    isAutoMoving = false;
    // Qui potresti aggiungere o rimuovere una classe per un effetto visivo
  }

    // Ritorna la linea al centro con animazione e riavvia l'oscillazione
    function resetAndStartAuto() {
        if (isAutoMoving) return; 

        const currentPct = parseFloat(handle.style.left) || centerPercent;
        const duration = 500; 
        const startTime = performance.now();

        function easeBack() {
            const elapsed = performance.now() - startTime;
            const progress = Math.min(1, elapsed / duration);

            // Easing cubico
            const easedProgress = 1 - Math.pow(1 - progress, 3); 

            const newPct = currentPct + (centerPercent - currentPct) * easedProgress;
            setPercent(newPct);

            if (progress < 1) {
                requestAnimationFrame(easeBack);
            } else {
                // Riavvia l'oscillazione dal centro
                isAutoMoving = true;
                theta = 0; 
                requestAnimationFrame(animateOscillation);
            }
        }
        requestAnimationFrame(easeBack);
    }
    
  // ✨ Animazione sinusoidale standard
  function animateOscillation() {
    if (!isAutoMoving) {
        return;
    }
    theta += speed;
    const eased = Math.sin(theta); 
    const pct = centerPercent + eased * amplitude;

    setPercent(pct);
    requestAnimationFrame(animateOscillation);
  }
  requestAnimationFrame(animateOscillation);


  // --- Interazioni Desktop ---
  handle.addEventListener('mousedown', (e) => {
    isDragging = true;
    container.classList.add('dragging');
    stopAuto();
    e.preventDefault();
  });
  window.addEventListener('mouseup', () => {
    isDragging = false;
    container.classList.remove('dragging');
  });
  window.addEventListener('mousemove', (e) => {
    if (!isDragging) return;
    setPercent(percentFromClientX(e.clientX));
  });

  // --- Interazioni Touch ---
  handle.addEventListener('touchstart', (e) => {
    isDragging = true;
    container.classList.add('dragging');
    stopAuto();
  }, { passive: true });
  window.addEventListener('touchend', () => {
    // 1. Controlla se l'utente stava effettivamente trascinando
    if (isDragging) {
    // 2. Resetta i flag di trascinamento
        isDragging = false;
        container.classList.remove('dragging');
    // 3. Avvia il rientro al centro e l'oscillazione
        resetAndStartAuto(); // <-- AGGIUNTO IL RIAVVIO
    }
});
  window.addEventListener('touchmove', (e) => {
    if (!isDragging) return;
    const touch = e.touches && e.touches[0];
    if (!touch) return;
    setPercent(percentFromClientX(touch.clientX));
  }, { passive: true });

  // ? Pausa all'ingresso del mouse/touch
  container.addEventListener('mouseover', stopAuto); 
  container.addEventListener('touchstart', stopAuto, { once: true });
  
  // ▶️ Ritorno al centro e Riavvio all'uscita del mouse
  container.addEventListener('mouseleave', () => {
    // Si riavvia solo se l'utente non sta trascinando attivamente
    if (!isDragging) { 
      resetAndStartAuto();
    }
  });
});
</script>

Puoi incollare il codice sopra in un blocco “HTML personalizzato” di WordPress, Brizy o Divi.

Sostituisci semplicemente gli URL https://tuosito.com/path/prima.jpg e https://tuosito.com/path/dopo.jpg con le tue immagini.


Disclosure: i collegamenti in questo sito sono "link di affiliazione". Ciò significa che se fai clic sul collegamento e acquisti l'articolo, riceveremo una commissione di affiliazione. Divi è un marchio registrato di Elegant Themes, Inc. Questo sito non fa parte di Elegant Themes inc.