medias · comparaison · slider

Comparaison avant / après

Image 1 en dessous, image 2 au-dessus : le curseur découpe la couche du dessus pour révéler celle du dessous. Version format carte — voir 'Slider avant/après' pour la version plein écran.

Voir le code source
<style>
.bn-compare-card {
  max-width: 500px;
  padding: 1rem;
  font-family: 'Inter', sans-serif;
  background: #0B0F10;
}

.bn-compare-card__stage {
  position: relative;
  overflow: hidden;
  border-radius: 4px;

  /* Mise à jour par script.js à chaque déplacement du curseur :
     pilote à la fois la découpe de la couche 2 et la position du
     repère visuel */
  --reveal: 50%;
}

.bn-compare-card__layer1 {
  width: 100%;
  display: block;
}

/* La couche 2 est positionnée exactement par-dessus la couche 1,
   puis "coupée" avec clip-path pour ne montrer que sa partie gauche,
   jusqu'à la position du curseur */
.bn-compare-card__layer2-wrap {
  position: absolute;
  inset: 0;
  clip-path: inset(0 calc(100% - var(--reveal)) 0 0);
}

.bn-compare-card__layer2 {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.bn-compare-card__handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--reveal);
  transform: translateX(-50%);

  width: 2px;
  background: #E6E4DD;
  pointer-events: none;
}

.bn-compare-card__handle span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);

  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #E6E4DD;
  color: #0B0F10;

  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.9rem;
}

.bn-compare-card__label {
  position: absolute;
  top: 12px;
  padding: 0.25rem 0.7rem;
  background: rgba(5, 8, 8, 0.7);
  border-radius: 999px;
  color: #E6E4DD;
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  pointer-events: none;
}

.bn-compare-card__label--left { left: 12px; }
.bn-compare-card__label--right { right: 12px; }

/* Contrôle natif invisible, étiré sur toute la zone pour capter le
   clic/glisser n'importe où sur l'image */
.bn-compare-card__input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
}

.bn-compare-card__caption {
  margin: 0.75rem 0 0;
  color: #979793;
  font-size: 0.8rem;
}

</style>

<div class="bn-compare-card" data-fx-root>
  <div class="bn-compare-card__stage">
    <!-- Couche 1 (dessous) : l'image "avant", toujours entièrement visible -->
    <img class="bn-compare-card__layer1" src="https://placehold.co/700x460/1D2324/E6E4DD?text=AVANT" alt="Avant retouche" />

    <!-- Couche 2 (dessus) : l'image "après", découpée par le curseur -->
    <div class="bn-compare-card__layer2-wrap">
      <img class="bn-compare-card__layer2" src="https://placehold.co/700x460/C2410C/0B0F10?text=APRÈS" alt="Après retouche" />
    </div>

    <div class="bn-compare-card__handle" aria-hidden="true">
      <span>↔</span>
    </div>

    <span class="bn-compare-card__label bn-compare-card__label--left">Avant</span>
    <span class="bn-compare-card__label bn-compare-card__label--right">Après</span>

    <!-- Le vrai contrôle, natif et accessible au clavier -->
    <input
      type="range"
      class="bn-compare-card__input"
      min="0"
      max="100"
      value="50"
      aria-label="Curseur de comparaison avant/après"
    />
  </div>

  <p class="bn-compare-card__caption">Retouche colorimétrique &amp; contraste</p>
</div>


<script>
/* ==========================================================
   COMPARAISON AVANT / APRÈS
   Même principe que le slider avant/après plein écran : le
   <input type="range"> pilote une variable CSS "--reveal" qui
   découpe la couche du dessus (l'image "après") pour révéler
   la couche du dessous (l'image "avant").
   ========================================================== */

(function () {
  const root = document.querySelector('.bn-compare-card[data-fx-root]');
  if (!root) return;

  const input = root.querySelector('.bn-compare-card__input');
  const stage = root.querySelector('.bn-compare-card__stage');

  function update() {
    stage.style.setProperty('--reveal', `${input.value}%`);
  }

  input.addEventListener('input', update);
  update();
})();

</script>