Galerie✨ Premium

Zoom Lightbox

La photo grandit exactement depuis la vignette cliquée jusqu'au centre de l'écran, puis repart s'y ranger à la fermeture.

JSZoomTransform

Mis à jour le

Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Galerie comprend 44 effets, dont 6 gratuits. Découvrir la catégorie →

3 exemples d'usage

Photos épinglées le long d'un tracé de randonnée — Zoom Lightbox exemple 1

① Photos épinglées le long d'un tracé de randonnée

QuandDans le carnet Ostravelle, quatre photos sont posées sur la carte, à l'endroit où elles ont été prises. Un clic sur celle du col la fait grandir depuis son point sur le tracé.
PourquoiIci la position de la vignette est une information : la voir s'ouvrir depuis le col relie la photo au lieu. Une ouverture au centre, sans origine, ferait perdre ce lien.
RéglagesLa carte est le fond de la racine (background-image) ; .zlb-grid passe en display: block et chaque vignette est placée en position: absolute (74 px, bord blanc de 3 px). Capture : clic sur la vignette au 6e mouvement, fermeture par ✕ au 13e.
Échantillons de tissu d'un tapissier, ouverts depuis leur case — Zoom Lightbox exemple 2

② Échantillons de tissu d'un tapissier, ouverts depuis leur case

QuandSur la page de l'atelier Melizanne, le client parcourt six tissus ; il clique sur « Pois sable » pour voir le motif de près avant de commander un carré témoin.
PourquoiDans un nuancier, on compare des cases voisines ; voir la grande image sortir de sa case puis y retourner aide à garder en tête laquelle on regarde.
RéglagesGrille de trois colonnes avec nom et matière sous chaque vignette, --zlb-backdrop: rgba(40, 32, 24, 0.9) pour un fond brun.
Photo reçue dans une conversation, agrandie depuis la bulle — Zoom Lightbox exemple 3

③ Photo reçue dans une conversation, agrandie depuis la bulle

QuandInès envoie une photo de la plage ; on touche la miniature dans la bulle, elle grandit jusqu'au plein écran, et un toucher à côté la renvoie dans la bulle.
PourquoiC'est le geste attendu dans une messagerie : l'image semble sortir du fil et y revenir, on ne perd pas sa place dans la conversation.
RéglagesUne seule vignette, de la largeur de la bulle (170 px, --zlb-radius: 11px). La racine est posée dans la bulle elle-même.

Comment ça marche

Technique dite FLIP. Au clic sur un bouton .zlb-thumb, le script ouvre le <dialog>, attend que la grande image connaisse sa taille (img.decode()), puis mesure deux rectangles : celui de la vignette et celui de l'image à sa place finale. Il en déduit un décalage et une échelle, et lance avec element.animate() une animation qui part de la vignette (translate + scale) pour arriver à transform: none.

L'aller dure 400 ms avec la courbe d'origine de l'effet (cubic-bezier(0.175, 0.885, 0.32, 1.275), un petit dépassement) ; le fond noir à 90 % apparaît en fondu pendant ce temps. À la fermeture (✕, Échap ou clic sur le fond), la même animation est jouée à l'envers, en 400 ms accélérées, vers la position de la vignette à cet instant ; le dialog se ferme ensuite.

Mesuré dans Chromium, Firefox et WebKit : au départ de l'animation, le centre de l'image coïncide au pixel près avec celui de la vignette. Si la vignette et l'image n'ont pas les mêmes proportions, l'image est légèrement étirée pendant les 400 ms, puis retrouve ses proportions.

Accessibilité

  • Boutons : chaque vignette est un <button> au Tab, ouverte par Entrée ou Espace ; son alt devient celui de la grande image.
  • Dialog modal : rôle dialog et nom « Visionneuse d'images », page derrière inerte, focus sur ✕ à l'ouverture, Échap pour fermer.
  • Focus rendu : il revient sur la vignette d'où l'image est partie, là où l'image vient de se ranger.
  • Mouvement réduit : avec prefers-reduced-motion: reduce, aucun zoom ni fondu ; l'image apparaît directement au centre et disparaît d'un coup.
  • Toucher : un toucher ouvre comme un clic. Il n'y a pas de navigation entre images dans cette visionneuse : une image par ouverture.

Compatibilité navigateur

element.animate() existe depuis Chrome 36, Firefox 48 et Safari 13.1, img.decode() depuis Chrome 64, Firefox 68 et Safari 11.1 ; le facteur limitant reste le <dialog> modal (Firefox 98, Safari 15.4) et aspect-ratio (Chrome 88). Point de départ du zoom mesuré dans Chromium 151, Firefox 153 et WebKit 26.5, avec deux galeries sur la page.

Chrome 88+✓ Complet (mesuré)
Firefox 98+✓ Complet (mesuré)
Safari 15.4+✓ Complet (mesuré sur WebKit)
Edge 88+✓ Complet (moteur Chromium)
Mobile iOS 15.4+✓ Complet (non mesuré sur appareil)
Android Chrome 88+✓ Complet (toucher mesuré)

Sans img.decode(), le zoom attend l'événement load de l'image. Sans showModal(), rien ne s'ouvre et les vignettes restent de simples photos.

Le code

Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :

index.html — structure
<div class="fx-0173-root">
  <div class="zlb-grid">
    <button type="button" class="zlb-thumb" aria-haspopup="dialog"><img src="photo.jpg" alt="Dégradé cyan vers émeraude" width="600" height="400"></button>
    <button type="button" class="zlb-thumb" aria-haspopup="dialog"><img src="photo.jpg" alt="Dégradé ambre vers rouge" width="600" height="400"></button>
    <button type="button" class="zlb-thumb" aria-haspopup="dialog"><img src="photo.jpg" alt="Dégradé indigo vers violet" width="600" height="400"></button>
    <button type="button" class="zlb-thumb" aria-haspopup="dialog"><img src="photo.jpg" alt="Dégradé violet vers cyan" width="600" height="400"></button>
  </div>
  <dialog class="zlb-viewer" aria-label="Visionneuse d'images">
    <div class="zlb-content">
      <button type="button" class="zlb-close" aria-label="Fermer"><svg>…</svg></button>
      <img class="zlb-image" alt="">
    </div>
  </dialog>
</div>

Paiement unique, sans abonnement — le code est à toi pour toujours

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
Durée du zoom (JS — CLOSE_MS) 400 ms Sert à l'aller, au retour et au délai avant fermeture ; ajustez aussi la transition d'opacité du CSS.
Courbe d'ouverture (JS — easing dans zoomBetween) cubic-bezier(0.175, 0.885, 0.32, 1.275) Le dernier nombre au-dessus de 1 donne le petit rebond ; ease-out pour une arrivée sans dépassement.
Largeur des vignettes (CSS — --zlb-thumb) 120px Format 3:2 ; vous pouvez aussi positionner chaque vignette librement, le zoom part toujours de sa vraie place.
Fond (CSS — --zlb-backdrop) rgba(0, 0, 0, 0.9) Teinte du voile qui se fonce pendant le zoom.
Arrondis (CSS — --zlb-radius, --zlb-radius-lg) 0.5rem, 1rem Coins de la vignette et de l'image agrandie.
Photo pleine résolution (HTML — data-full) absent Chargée à l'ouverture ; le zoom démarre quand elle est décodée.

FAQ

La vignette est recadrée au format 3:2 alors que votre photo peut être plus haute ou plus large : l'animation passe d'un rectangle à l'autre en étirant légèrement l'image pendant 400 ms. Donnez à .zlb-thumb le même format que vos photos pour un zoom parfaitement proportionné.
À la fermeture, la position de la vignette est mesurée à nouveau : l'image retourne là où la vignette se trouve à ce moment, même si elle a bougé.
Elles feraient le même trajet, mais elles n'existent que depuis Chrome 111, Safari 18 et Firefox 144, et demandent un nom de transition unique par image. Le calcul FLIP avec element.animate() marche partout où le <dialog> marche, sans réglage.