Galerie avec effet Lightbox en JavaScript et CSS
Le code suivant permet de zoomer sur des vignettes avec un effet Lightbox écrit le plus simplement possible, en HTML, CSS et JavaScript.
Page index.html
Commençons par le code HTML. Un titre, deux petites images et deux paragraphes. Le code HTML est le plus pur possible. Pas de liens, ni même de classes sur les images.
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Petits mammifères</title>
<meta charset="utf-8">
<link rel="stylesheet" href="lightbox.css">
</head>
<body>
<h1>Petits mammifères</h1>
<img src="images/vignette-hamster.jpg" alt="Hamster">
<img src="images/vignette-herisson.jpg" alt="Hérisson">
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Veritatis, magni eligendi. Sequi possimus enim exercitationem ipsa. Adipisci optio nesciunt atque. Molestias ipsam iusto sapiente repellat praesentium voluptates necessitatibus impedit maxime? Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quam maxime quis perspiciatis itaque aspernatur voluptates, explicabo veniam reprehenderit doloribus ut odio debitis facilis vero quaerat ipsa. Iure excepturi quae fugiat. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Totam iste ducimus iusto voluptatibus quaerat nesciunt maxime beatae sed quod dolor repudiandae ipsa, ad consectetur quas possimus asperiores nemo autem id.</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ex placeat illo consequuntur adipisci, illum nobis nostrum unde ratione optio corrupti veritatis aut accusamus ab nam? Perferendis veniam quae provident autem. Lorem, ipsum dolor sit amet consectetur adipisicing elit. Perferendis, officia atque ullam id explicabo quidem enim eveniet ut, reiciendis consequuntur ipsam accusantium quibusdam officiis iusto quasi rem, neque sint. Officia. Lorem ipsum, dolor sit amet consectetur adipisicing elit. Possimus voluptas, dolores aperiam laudantium quam delectus modi, sunt natus temporibus iste omnis veritatis perspiciatis repellat error, quod recusandae nemo ex fugiat.</p>
<script src="lightbox.js"></script>
</body>
</html>
Le dossier images contient
- des grandes images d'une largeur de 1280 pixels,
- des vignettes d'une largeur de 250 pixels dont le nom commence par vignette- suivi du nom de la grande image correspondante.
Feuille de style externe style.css
La feuille de style est plus complexe. En cas de clic sur les vignettes, la grande image devra apparaître à l'intérieur d'une balise <div id="grande"> avec un fond à moitié opaque occupant toute la surface de la fenêtre, et de manière progressive, grâce à la propriété transition agissant sur la propriété opacity. Notez que la durée de la transition n'est pas précisée. Elle le sera en amont du code JavaScript.
La grande image insérée dans la balise <div> ne pourra dépasser 80% de la hauteur ou de la largeur de la fenêtre et sera centrée horizontalement et verticalement grâce aux propriétés flex, justify-content et align-items.
Les vignettes seront identifiées par leur nom contenant le mot vignette. Je préfère ici utiliser le sélecteur img[src*=vignette] plutôt que de charger le code HTML de classes. Ce sélecteur sera réutilisé dans le code JavaScript pour l'écoute des évènements click.
body {
font-family: Arial, Helvetica, sans-serif;
}
img[src*=vignette] {
margin-right: 20px;
margin-bottom: 10px;
cursor: pointer;
}
#grande {
transition-property: opacity;
transition-timing-function: ease-in-out;
opacity: 0;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
z-index: -1;
display: flex;
justify-content: center;
align-items: center;
}
#grande>img {
max-width: 80vw;
max-height: 80vh;
}
Au départ, la balise <div> est transparente (opacity: 0) et se trouve sous le contenu de la page (z-index: -1). C'est le code JavaScript qui fera apparaître et disparaître la balise <div> contenant la grande image.
Code JavaScript lightbox.js
Le code JavaScript va ajouter les évènements click sur les vignettes. Lorsqu'on cliquera sur les vignettes, on insérera la grande image correspondante dans la balise <div> que l'on mettra au premier plan, suivi d'une apparition progressive. Lorsque l'utilisateur cliquera sur la grande image, la balise <div> disparaitra progressivement avant de se retrouver à nouveau sous le contenu. J'utilise la méthode setTimeout() qui permet d'attendre la phase de disparition (opacité vers transparence) avant de mettre l'ensemble en arrière plan. Cela évite beaucoup de bugs.
Voici le code commenté :
// Durée de l'apparition et disparition de l'image en millisecondes
const duree = 300;
// Création de la balise <div id="grande"> en fin de page
const divgrande = document.createElement("div");
divgrande.id = "grande";
document.body.appendChild(divgrande);
// Application de la durée de transition
divgrande.style.transitionDuration = duree + "ms";
// Si clic sur les vignettes
function clic_vignettes() {
// On récupère la source de la vignette sur laquelle l'utilisateur a cliqué
let source_vignette = this.getAttributeNode("src").value;
// On récupère le nom de la grande image à partir de la source de la vignette (retrait des 16 premiers caractères : "images/vignette-")
let nom_grande = source_vignette.substr(16);
// On insère la grande image dans la balise div
divgrande.innerHTML = "<img src='images/" + nom_grande + "'>";
// Div au premier plan
divgrande.style.zIndex = 1;
// Div opaque (progressivement grâce à la propriété CSS transition)
divgrande.style.opacity = 1;
// Curseur avec la petite main pour inviter au clic de sortie
divgrande.style.cursor = 'pointer';
// On greffe un évènement click pour fermer la grande image
divgrande.addEventListener("click", clic_grande);
}
// Si clic sur la grande image
function clic_grande() {
// On enlève l'écoute du click sur la grande image pour éviter les bugs
divgrande.removeEventListener("click", clic_grande);
// Transparence progressive
divgrande.style.opacity = 0;
// Une fois que l'image est transparente, on masque le div en arrière plan
setTimeout(masque_grande, duree);
}
// Div en arrière plan et curseur normal
function masque_grande() {
divgrande.style.zIndex = -1;
divgrande.style.cursor = 'initial';
}
// On lance l'écoute des clics sur les vignettes
const vignettes = document.querySelectorAll("img[src*=vignette]");
vignettes.forEach(function (element) {
element.addEventListener("click", clic_vignettes);
});
Vous pouvez régler à votre convenance la durée de l'opacité/transparence sur la variable duree en début de code.
Vidéo
La fabrication de cet effet Lightbox est expliqué en détail dans cette vidéo de 30 minutes.