Dans ce tutoriel je vous propose de découvrir comment créer une Lightbox en JavaScript. L'objectif de ce code est de permettre à l'utilisateur de voir une image en grandsans avoir à quitter la page actuel.

Pourquoi ne pas utiliser une librairie ?

On peut tout de suite se demander pourquoi ne pas utiliser une librairie tierce. Il y a plusieurs raisons pour cela :

  • Nos besoins sont assez spécifiques et on risque de passer plus de temps à trouver une librairie qui fasse ce que l'on cherche qu'à coder le système soi-même.
  • Une librairie va couvrir beaucoup de cas qui ne sont pas nécessaire dans notre cas, ce qui a un impact négatif sur les performances et sur le poids de la librairie en question.

En revanche, il faudra du coup prendre du temps pour déboguer notre code afin de s'assurer que notre code fonctionne dans toutes les conditions (là où une librairie est souvent testée par la communauté).

La structure HTML

Pour la structure HTML nous allons essayer de rester le plus simple possible avec le minimum d'élément.

<div class="lightbox">
  <button class="lightbox__close">Fermer</button>
  <button class="lightbox__next">Suivant</button>
  <button class="lightbox__prev">Précédent</button>
  <div class="lightbox__container">
    <img src="chemin/vers/image.jpg" alt="">
  </div>
</div>

L'élément .lightbox sera positionner de manière fixed avec une couleur de fond opaque. L'élément .lightbox__container nous permettra de positionner convenablement l'image au centre de l'écran grâce au système de flexbox.

.lightbox__container {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  margin: 0 50px;
}

Pour le reste des éléments le placement se fait de manière classique et il n'y a pas grand chose à dire sur ce point.

La logique

La première étape de notre script sera de sélectionner tous les liens qui mènent vers des images. Pour cela il suffit de trouver tous les liens finissant par jpg, png, jpeg ou gif.

addEventListener

Lors du clic nous allons construire la structure HTML de notre lightbox et greffer les différents comportements.

  /**
   * @param {string} url URL de l'image
   * @return {HTMLElement}
   */
  buildDOM(url) {
    const dom = document.createElement('div')
    dom.classList.add('lightbox')
    dom.innerHTML = `<button class="lightbox__close">Fermer</button>
        <button class="lightbox__next">Suivant</button>
        <button class="lightbox__prev">Précédent</button>
        <div class="lightbox__container"></div>`
    dom.querySelector('.lightbox__close').addEventListener('click', this.close.bind(this))
    dom.querySelector('.lightbox__next').addEventListener('click', this.next.bind(this))
    dom.querySelector('.lightbox__prev').addEventListener('click', this.prev.bind(this))
    return dom
  }

Et nous allons ensuite lancer le chargement de l'image.

  /**
   * @param {string} url URL de l'image
   */
  loadImage (url) {
    this.url = null
    const image = new Image()
    const container = this.element.querySelector('.lightbox__container')
    const loader = document.createElement('div')
    loader.classList.add('lightbox__loader')
    container.innerHTML = ''
    container.appendChild(loader)
    image.onload = () => {
      container.removeChild(loader)
      container.appendChild(image)
      this.url = url
    }
    image.src = url
  }

Nous allons conserver l'url de l'image affichée afin de pouvoir retrouver la position de cette image dans notre galerie pour la navigation suivant et précédent.

  /**
   * @param {MouseEvent|KeyboardEvent} e 
   */
  next (e) {
    e.preventDefault()
    let i = this.images.findIndex(image => image === this.url)
    if (i === this.images.length - 1) {
      i = -1
    }
    this.loadImage(this.images[i + 1])
  }

  /**
   * @param {MouseEvent|KeyboardEvent} e 
   */
  prev (e) {
    e.preventDefault()
    let i = this.images.findIndex(image => image === this.url)
    if (i === 0) {
      i = this.images.length
    }
    this.loadImage(this.images[i - 1])
  }

Comment continuer ?

Si vous voulez pousser plus loin le script écrit dans cette vidéo voici quelques pistes à explorer :

  • Vérifier la compatibilité sur les différents navigateurs / périphérique.
  • Bloquer l'interface pendant le chargement d'une image (ou annuler le précédent chargement).
  • Améliorer le système de galerie en évitant les doubles et en créant un système de sous galeries.
  • Améliorer l'accessibilité en utilisant les attributs aria.
  • Créer des tests pour valider le fonctionnement de la lightbox.