モーダルイメージギャラリー(Lightbox)を自作する方法

自作するにあたり以下のサイトを参考にしています。

今回は写真ギャラリーの「Lightbox」をを自作する方法を紹介します。

サイト参考版

まず、一番シンプルに参考にしてきたサイトのコードそのまま利用した場合のバージョンになります。

サンプル

HTMLコード

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <title>Slideshow / Carousel demo(1)</title>
  <style type="text/css">
    .row > .column {
      padding: 0 8px;
    }
    .row:after {
      content: "";
      display: table;
      clear: both;
    }
    /* Create four equal columns that floats next to eachother */
    .column {
      float: left;
      width: 25%;
    }
    /* The Modal (background) */
    .modal {
      display: none;
      position: fixed;
      z-index: 1;
      padding-top: 100px;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      overflow: auto;
      background-color: black;
    }
    /* Modal Content */
    .modal-content {
      position: relative;
      background-color: #fefefe;
      margin: auto;
      padding: 0;
      width: 90%;
      max-width: 1200px;
    }
    /* The Close Button */
    .close {
      color: white;
      position: absolute;
      top: 10px;
      right: 25px;
      font-size: 35px;
      font-weight: bold;
    }
    .close:hover,
    .close:focus {
      color: #999;
      text-decoration: none;
      cursor: pointer;
    }
    /* Hide the slides by default */
    .mySlides {
      display: none;
    }
    /* Next & previous buttons */
    .prev,
    .next {
      cursor: pointer;
      position: absolute;
      top: 50%;
      width: auto;
      padding: 16px;
      margin-top: -50px;
      color: white;
      font-weight: bold;
      font-size: 20px;
      transition: 0.6s ease;
      border-radius: 0 3px 3px 0;
      user-select: none;
      -webkit-user-select: none;
    }
    /* Position the "next button" to the right */
    .next {
      right: 0;
      border-radius: 3px 0 0 3px;
    }
    /* On hover, add a black background color with a little bit see-through */
    .prev:hover,
    .next:hover {
      background-color: rgba(0, 0, 0, 0.8);
    }
    /* Number text (1/3 etc) */
    .numbertext {
      color: #f2f2f2;
      font-size: 12px;
      padding: 8px 12px;
      position: absolute;
      top: 0;
    }
    /* Caption text */
    .caption-container {
      text-align: center;
      background-color: black;
      padding: 2px 16px;
      color: white;
    }
    img.demo {
      opacity: 0.6;
    }
    .active,
    .demo:hover {
      opacity: 1 !important;
    }
    img.hover-shadow {
      transition: 0.3s;
    }
    .hover-shadow:hover {
      box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
    }
  </style>
</head>
<body>
  <div style="width:80%">
    <!-- Images used to open the lightbox -->
    <div class="row" >
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06344.jpg" onclick="openModal();currentSlide(1)" class="hover-shadow" style="width:100%">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07591.jpg" onclick="openModal();currentSlide(2)" class="hover-shadow" style="width:100%">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07708.jpg" onclick="openModal();currentSlide(3)" class="hover-shadow" style="width:100%">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06513.jpg" onclick="openModal();currentSlide(4)" class="hover-shadow" style="width:100%">
      </div>
    </div>
    <!-- The Modal/Lightbox -->
    <div id="myModal" class="modal" >
      <span class="close cursor" onclick="closeModal()">&times;</span>
      <div class="modal-content"  style="width:45%;background-color:inherit !important;">
        <div class="mySlides">
          <div class="numbertext">1 / 4</div>
          <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06344.jpg" style="width:100%">
        </div>
        <div class="mySlides">
          <div class="numbertext">2 / 4</div>
          <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07591.jpg" style="width:100%">
        </div>
        <div class="mySlides">
          <div class="numbertext">3 / 4</div>
          <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07708.jpg" style="width:100%">
        </div>
        <div class="mySlides">
          <div class="numbertext">4 / 4</div>
          <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06513.jpg" style="width:100%">
        </div>
        <!-- Next/previous controls -->
        <a class="prev" onclick="plusSlides(-1)" >&#10094;</a>
        <a class="next" onclick="plusSlides(1)"  >&#10095;</a>
        <!-- Caption text -->
        <div class="caption-container">
          <p id="caption"></p>
        </div>
        <!-- Thumbnail image controls -->
        <div class="column">
          <img class="demo" src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06344.jpg" onclick="currentSlide(1)" alt="レッサーパンダ"  style="width:100%">
        </div>
        <div class="column">
          <img class="demo" src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07591.jpg" onclick="currentSlide(2)" alt="カピバラ"  style="width:100%">
        </div>
        <div class="column">
          <img class="demo" src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07708.jpg" onclick="currentSlide(3)" alt="ペンギン"  style="width:100%">
        </div>
        <div class="column">
          <img class="demo" src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06513.jpg" onclick="currentSlide(4)" alt="ネコ"  style="width:100%">
        </div>
      </div>
    </div>
  </div>
  <script type="text/javascript">
    // Open the Modal
    function openModal() {
      document.getElementById("myModal").style.display = "block";
    }
    // Close the Modal
    function closeModal() {
      document.getElementById("myModal").style.display = "none";
    }
    var slideIndex = 1;
    showSlides(slideIndex);
    // Next/previous controls
    function plusSlides(n) {
      showSlides(slideIndex += n);
    }
    // Thumbnail image controls
    function currentSlide(n) {
      showSlides(slideIndex = n);
    }
    function showSlides(n) {
      var i;
      var slides = document.getElementsByClassName("mySlides");
      var dots = document.getElementsByClassName("demo");
      var captionText = document.getElementById("caption");
      if (n > slides.length) {slideIndex = 1}
      if (n < 1) {slideIndex = slides.length}
      for (i = 0; i < slides.length; i++) {
        slides[i].style.display = "none";
      }
      for (i = 0; i < dots.length; i++) {
        dots[i].className = dots[i].className.replace(" active", "");
      }
      slides[slideIndex-1].style.display = "block";
      dots[slideIndex-1].className += " active";
      captionText.innerHTML = dots[slideIndex-1].alt;
    }
  </script>
</body>
</html>

デモ

実装方法

スタイルシート定義

<style type="text/css">
  .row > .column {
    padding: 0 8px;
  }
  .row:after {
    content: "";
    display: table;
    clear: both;
  }
  /* Create four equal columns that floats next to eachother */
  .column {
    float: left;
    width: 25%;
  }
  /* The Modal (background) */
  .modal {
    display: none;
    position: fixed;
    z-index: 1;
    padding-top: 100px;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow: auto;
    background-color: black;
  }
  /* Modal Content */
  .modal-content {
    position: relative;
    background-color: #fefefe;
    margin: auto;
    padding: 0;
    width: 90%;
    max-width: 1200px;
  }
  /* The Close Button */
  .close {
    color: white;
    position: absolute;
    top: 10px;
    right: 25px;
    font-size: 35px;
    font-weight: bold;
  }
  .close:hover,
  .close:focus {
    color: #999;
    text-decoration: none;
    cursor: pointer;
  }
  /* Hide the slides by default */
  .mySlides {
    display: none;
  }
  /* Next & previous buttons */
  .prev,
  .next {
    cursor: pointer;
    position: absolute;
    top: 50%;
    width: auto;
    padding: 16px;
    margin-top: -50px;
    color: white;
    font-weight: bold;
    font-size: 20px;
    transition: 0.6s ease;
    border-radius: 0 3px 3px 0;
    user-select: none;
    -webkit-user-select: none;
  }
  /* Position the "next button" to the right */
  .next {
    right: 0;
    border-radius: 3px 0 0 3px;
  }
  /* On hover, add a black background color with a little bit see-through */
  .prev:hover,
  .next:hover {
    background-color: rgba(0, 0, 0, 0.8);
  }
  /* Number text (1/3 etc) */
  .numbertext {
    color: #f2f2f2;
    font-size: 12px;
    padding: 8px 12px;
    position: absolute;
    top: 0;
  }
  /* Caption text */
  .caption-container {
    text-align: center;
    background-color: black;
    padding: 2px 16px;
    color: white;
  }
  img.demo {
    opacity: 0.6;
  }
  .active,
  .demo:hover {
    opacity: 1 !important;
  }
  img.hover-shadow {
    transition: 0.3s;
  }
  .hover-shadow:hover {
    box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
  }
</style>

HTMLマークアップ

まず、画像を設置します。

<div class="row" >
  <div class="column" style="padding:0px">
    <img src="(画像URI)" onclick="openModal();currentSlide(1)" class="hover-shadow" style="width:100%" />
  </div>
  ...
</div>

イメージタグ(<img>)を設置し、クリックイベントに『openModal()』と『currentSlide()』を設定します。currentSlide()の引数には、後で設置するスライドの番号を設定してください。

次にモーダル領域を生成します。

<div id="myModal" class="modal" >
  <span class="close cursor" onclick="closeModal()">&times;</span><!-- 閉じるボタン -->
  <div class="modal-content"  style="height:45%;background-color:inherit !important;">

    ...
  </div>
</div>

まず、DIV領域を設定し、class『modal』を指定します。

次に、モーダルの内容としてDIV領域を生成し、class『modal-content』を設定します。

また、合わせて、閉じるボタンとして、SPANに、class『close』を指定し、クリックイベントに『closeModal()』指定してください。閉じる記号としては『』(&times:)を指定してあります。

<div id="myModal" class="modal" >
  <span class="close cursor" onclick="closeModal()">&times;</span><!-- 閉じるボタン -->
  <div class="modal-content"  style="height:45%;background-color:inherit !important;">
    <div class="mySlides">
      <div class="numbertext">1 / 4</div>
      <img src="(画像URI)" style="width:100%">
    </div>
    ...
  </div>
</div>

スライド領域として、DIVにclass『mySlides』を指定します。その配下に、モーダル表示時に表示する画像をイメージタグ(<img>)を設定します。

次に、『次へ』ボタンと『前へ』ボタンを設置します。

<div id="myModal" class="modal" >
  <span class="close cursor" onclick="closeModal()">&times;</span><!-- 閉じるボタン -->
  <div class="modal-content"  style="height:45%;background-color:inherit !important;">
    <div class="mySlides">
      <div class="numbertext">1 / 4</div>
      <img src="(画像URI)" style="width:100%">
    </div>
    ...
    <!-- Next/previous controls -->
    <a class="prev" onclick="plusSlides(-1)" >&#10094;</a>
    <a class="next" onclick="plusSlides(1)"  >&#10095;</a>
  </div>
</div>

アンカータグ(<a>)に、class『prev』を指定し、クリックイベントとして『plusSlides(-1)』を設定すると、『前へ』ボタンになります。

アンカータグ(<a>)に、class『next』を指定し、クリックイベントとして『plusSlides(1)』を設置すると、『次へ』ボタンいなります。

<div id="myModal" class="modal" >
  <span class="close cursor" onclick="closeModal()">&times;</span><!-- 閉じるボタン -->
  <div class="modal-content"  style="height:45%;background-color:inherit !important;">
    <div class="mySlides">
      <div class="numbertext">1 / 4</div>
      <img src="(画像URI)" style="width:100%">
    </div>
    ...
    <!-- Next/previous controls -->
    <a class="prev" onclick="plusSlides(-1)" >&#10094;</a>
    <a class="next" onclick="plusSlides(1)"  >&#10095;</a>
    <!-- Caption text -->
    <div class="caption-container">
      <p id="caption"></p>
    </div>
  </div>
</div>

さらに、キャプション領域を設定します。

DIV領域に、class『caption-container』を設定し、配下に、ID『caption』の領域を生成しておきます。

<div id="myModal" class="modal" >
  <span class="close cursor" onclick="closeModal()">&times;</span><!-- 閉じるボタン -->
  <div class="modal-content"  style="height:45%;background-color:inherit !important;">
    <div class="mySlides">
      <div class="numbertext">1 / 4</div>
      <img src="(画像URI)" style="width:100%">
    </div>
    ...
    <!-- Next/previous controls -->
    <a class="prev" onclick="plusSlides(-1)" >&#10094;</a>
    <a class="next" onclick="plusSlides(1)"  >&#10095;</a>
    <!-- Caption text -->
    <div class="caption-container">
      <p id="caption"></p>
    </div>
    <!-- Thumbnail image controls -->
    <div class="column">
      <img class="demo" src="(画像URI)" onclick="currentSlide(1)" alt="(キャプション)"  style="width:100%">
    </div>
    ...
  </div>
</div>

最後に、サムネイル領域を生成します。DIV領域を設定し、class『column』を指定します。その配下に、サムネイル用の画像をイメージタグ(<img>)で設定します。classには『demo』を指定してください。また、alt属性に文字列を設定すると、その文字列がキャプションになります。

Javascriptコード追加

<script type="text/javascript">
  // Open the Modal
  function openModal() {
    document.getElementById("myModal").style.display = "block";
  }
  // Close the Modal
  function closeModal() {
    document.getElementById("myModal").style.display = "none";
  }
  var slideIndex = 1;
  showSlides(slideIndex);
  // Next/previous controls
  function plusSlides(n) {
    showSlides(slideIndex += n);
  }
  // Thumbnail image controls
  function currentSlide(n) {
    showSlides(slideIndex = n);
  }
  function showSlides(n) {
    var i;
    var slides = document.getElementsByClassName("mySlides");
    var dots = document.getElementsByClassName("demo");
    var captionText = document.getElementById("caption");
    if (n > slides.length) {slideIndex = 1}
    if (n < 1) {slideIndex = slides.length}
    for (i = 0; i < slides.length; i++) {
      slides[i].style.display = "none";
    }
    for (i = 0; i < dots.length; i++) {
      dots[i].className = dots[i].className.replace(" active", "");
    }
    slides[slideIndex-1].style.display = "block";
    dots[slideIndex-1].className += " active";
    captionText.innerHTML = dots[slideIndex-1].alt;
  }
</script>

最後に、Javascriptコードを追加すれば、完了です。

モーダルギャラリー領域およびサムネイルを自動生成するようにしてみた

モーダル領域を毎回HTMLでマークアップするのも面倒ですし、サムネイル数や写真数などは変わる可能性がるので、これらを動的に生成するようにしてみます。

HTMLコード

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <title>Slideshow / Carousel demo(2)</title>
  <style type="text/css">
    .row > .column {
      padding: 0 8px;
    }
    .row:after {
      content: "";
      display: table;
      clear: both;
    }
    /* Create four equal columns that floats next to eachother */
    .column {
      float: left;
      width: 25%;
    }
    /* The Modal (background) */
    .modal {
      display: none;
      position: fixed;
      z-index: 1;
      padding-top: 100px;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      overflow: auto;
      background-color: black;
    }
    /* Modal Content */
    .modal-content {
      position: relative;
      background-color: #fefefe;
      margin: auto;
      padding: 0;
      width: 90%;
      max-width: 1200px;
    }
    /* The Close Button */
    .close {
      color: white;
      position: absolute;
      top: 10px;
      right: 25px;
      font-size: 35px;
      font-weight: bold;
    }
    .close:hover,
    .close:focus {
      color: #999;
      text-decoration: none;
      cursor: pointer;
    }
    /* Hide the slides by default */
    .mySlides {
      display: none;
    }
    /* Next & previous buttons */
    .prev,
    .next {
      cursor: pointer;
      position: absolute;
      top: 50%;
      width: auto;
      padding: 16px;
      margin-top: -50px;
      color: white;
      font-weight: bold;
      font-size: 20px;
      transition: 0.6s ease;
      border-radius: 0 3px 3px 0;
      user-select: none;
      -webkit-user-select: none;
    }
    /* Position the "next button" to the right */
    .next {
      right: 0;
      border-radius: 3px 0 0 3px;
    }
    /* On hover, add a black background color with a little bit see-through */
    .prev:hover,
    .next:hover {
      background-color: rgba(0, 0, 0, 0.8);
    }
    /* Number text (1/3 etc) */
    .numbertext {
      color: #f2f2f2;
      font-size: 12px;
      padding: 8px 12px;
      position: absolute;
      top: 0;
    }
    /* Caption text */
    .caption-container {
      text-align: center;
      background-color: black;
      padding: 2px 16px;
      color: white;
    }
    img.demo {
      opacity: 0.6;
    }
    .active,
    .demo:hover {
      opacity: 1 !important;
    }
    img.hover-shadow {
      transition: 0.3s;
    }
    .hover-shadow:hover {
      box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
    }
  </style>
</head>
<body>
  <div style="width:80%">
    <!-- Images used to open the lightbox -->
    <div class="row" >
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06344.jpg" class="hover-shadow" style="width:100%" alt="レッサーパンダ">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07591.jpg" class="hover-shadow" style="width:100%" alt="カピバラ">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07708.jpg" class="hover-shadow" style="width:100%" alt="ペンギン">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06513.jpg" class="hover-shadow" style="width:100%" alt="ネコ">
      </div>
    </div>
  </div>
  <script type="text/javascript">
    var myModal = document.createElement("div");
    myModal.className = "modal";
    myModal.id = "myModal";
    var btnClose = document.createElement("span");
    btnClose.className = "close cursor";
    btnClose.innerHTML = "&times;"
    btnClose.addEventListener( 'click',  function() {
        closeModal();
      }, false 
    );
    var modalContent = document.createElement("div");
    modalContent.className = "modal-content";
    modalContent.style.width = "45%";
    modalContent.style.backgroundColor = "inherit"

    var slides = document.querySelectorAll(".column img");

    if ( slides != undefined  ) {
      var nCount = slides.length;

      for ( var i=0; i < nCount; i++ ) {
        var imgObj = slides[i];
        /* イベント設定 */
        setSlideClickEvent(imgObj,i+1);
        var mySlide = document.createElement("div");
        mySlide.className = "mySlides";

        var numberText = document.createElement("div");
        numberText.className = "numbertext";
        numberText.innerHTML =  String(i+1) + " / " + String(nCount);
        var lightboxSlide = document.createElement("img");
        lightboxSlide.src = imgObj.src;
        lightboxSlide.style.width = "100%";
        mySlide.appendChild(numberText);
        mySlide.appendChild(lightboxSlide);
        modalContent.appendChild(mySlide);
      }

      if ( nCount > 1 ) {
        var btnPrev = document.createElement("a");
        btnPrev.className = "prev";
        btnPrev.innerHTML = "&#10094;";
        btnPrev.addEventListener( 'click',  function() {
            plusSlides(-1);
          }, false 
        );

        var btnNext = document.createElement("a");
        btnNext.className = "next";
        btnNext.innerHTML = "&#10095";
        btnNext.addEventListener( 'click',  function() {
            plusSlides(1);
          }, false 
        );
        modalContent.appendChild(btnPrev);
        modalContent.appendChild(btnNext);
      }

      var captionArea = document.createElement("div");
      captionArea.className = "caption-container";

      var captionText = document.createElement("p");
      captionText.id = "caption";

      captionArea.appendChild(captionText);
      modalContent.appendChild(captionArea);

      for ( var i=0; i < nCount; i++ ) {
        var imgObj = slides[i];

        /* サムネイル作成 */
        var thumbArea = document.createElement("div");
        thumbArea.className = "column";
        thumbArea.style.width =  String((100 / nCount)) + '%';

        var thumbnail = document.createElement("img");
        thumbnail.src = imgObj.src;
        thumbnail.className = "demo";
        thumbnail.style.width = "100%";
        thumbnail.alt = imgObj.alt;

        thumbArea.appendChild(thumbnail);
        modalContent.appendChild(thumbArea);
        /* サムネイルクリック時のイベントを設定 */
        setThumbClickEvent(thumbnail,i+1);
      }
    }

    myModal.appendChild(btnClose);
    myModal.appendChild(modalContent);
    document.body.appendChild(myModal);

    // Open the Modal
    function openModal() {
      document.getElementById("myModal").style.display = "block";
    }
    // Close the Modal
    function closeModal() {
      document.getElementById("myModal").style.display = "none";
    }
    var slideIndex = 1;
    showSlides(slideIndex);
    // Next/previous controls
    function plusSlides(n) {
      showSlides(slideIndex += n);
    }
    // Thumbnail image controls
    function currentSlide(n) {
      showSlides(slideIndex = n);
    }
    function showSlides(n) {
      var i;
      var slides = document.getElementsByClassName("mySlides");
      var dots = document.getElementsByClassName("demo");
      var captionText = document.getElementById("caption");
      if (n > slides.length) {slideIndex = 1}
      if (n < 1) {slideIndex = slides.length}
      for (i = 0; i < slides.length; i++) {
        slides[i].style.display = "none";
      }
      for (i = 0; i < dots.length; i++) {
        dots[i].className = dots[i].className.replace(" active", "");
      }
      slides[slideIndex-1].style.display = "block";
      dots[slideIndex-1].className += " active";
      captionText.innerHTML = dots[slideIndex-1].alt;
    }
    function setSlideClickEvent(slide,idx) {
      if ( slide == undefined ) return;
      /* ボタンクリック時のイベント設定 */
      slide.addEventListener( 'click',  function() {
        openModal();
        currentSlide(idx);
      }, false );
    }
    function setThumbClickEvent(thumb,idx) {
      if ( thumb == undefined ) return;
      /* ボタンクリック時のイベント設定 */
      thumb.addEventListener( 'click',  function() {
        currentSlide(idx);
      }, false );
    }
  </script>
</body>
</html>

デモ

実装方法

基本的には、すべてJavascript側で対応するので、HTMLでは、画像を設定するだけです。

ただ、キャプションをサムネイルで設定するのではなく、画像のalt属性に設定してください。

<div class="row" >
  <div class="column" style="padding:0px">
    <img src="(画像URI1)" class="hover-shadow" style="width:100%" alt="(キャプション1)">
  </div>
  <div class="column" style="padding:0px">
    <img src="(画像URI2)" class="hover-shadow" style="width:100%" alt="(キャプション2)">
  </div>
  <div class="column" style="padding:0px">
    <img src="(画像URI3)" class="hover-shadow" style="width:100%" alt="(キャプション3)">
  </div>
  <div class="column" style="padding:0px">
    <img src="(画像URI4)" class="hover-shadow" style="width:100%" alt="(キャプション4)">
  </div>
</div>

あとは、Javascriptを実行するだけです。

モーダルイメージギャラリー(Lightbox)をライブラリ化してみた

サンプル

レッサーパンダ
カピバラ
ペンギン
ネコ

HTMLコード

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <title>Slideshow / Carousel demo(3)</title>
  <link rel="stylesheet" href="https://www.single-life.tokyo/demo/MyLightbox.css">
</head>
<body>
  <div style="width:80%">
    <div class="row" >
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06344.jpg" style="width:100%" alt="レッサーパンダ">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07591.jpg" style="width:100%" alt="カピバラ">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC07708.jpg" style="width:100%" alt="ペンギン">
      </div>
      <div class="column" style="padding:0px">
        <img src="https://www.single-life.tokyo/wp-content/uploads/2021/07/DSC06513.jpg" style="width:100%" alt="ネコ">
      </div>
    </div>
  </div>
  <script type="text/javascript" src="https://www.single-life.tokyo/demo/MyLightbox.js"></script>
  <script type="text/javascript">
   /* thumbVisible:falseにするとサムネイルが非表示 */
   var lightbox = new MyLightbox(".column img",{ thumbVisible:false } );
 </script>
</body>
</html>

CSSファイル(MyLightbox.css)

.row > .column {
  padding: 0 8px;
}

.row:after {
  content: "";
  display: table;
  clear: both;
}

/* Create four equal columns that floats next to eachother */
.column {
  float: left;
  width: 25%;
}

/* The Modal (background) */
.modal {
  display: none;
  position: fixed;
  z-index: 1;
  padding-top: 100px;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: black;
}

/* Modal Content */
.modal-content {
  position: relative;
  background-color: #fefefe;
  margin: auto;
  padding: 0;
  width: 90%;
  max-width: 1200px;
}

/* The Close Button */
.close {
  color: white;
  position: absolute;
  top: 10px;
  right: 25px;
  font-size: 35px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: #999;
  text-decoration: none;
  cursor: pointer;
}

/* Hide the slides by default */
.mySlides {
  display: none;
}

/* Next & previous buttons */
.prev,
.next {
  cursor: pointer;
  position: absolute;
  top: 50%;
  width: auto;
  padding: 16px;
  margin-top: -50px;
  color: white;
  font-weight: bold;
  font-size: 20px;
  transition: 0.6s ease;
  border-radius: 0 3px 3px 0;
  user-select: none;
  -webkit-user-select: none;
}

/* Position the "next button" to the right */
.next {
  right: 0;
  border-radius: 3px 0 0 3px;
}

/* On hover, add a black background color with a little bit see-through */
.prev:hover,
.next:hover {
  background-color: rgba(0, 0, 0, 0.8);
}

/* Number text (1/3 etc) */
.numbertext {
  color: #f2f2f2;
  font-size: 12px;
  padding: 8px 12px;
  position: absolute;
  top: 0;
}

/* Caption text */
.caption-container {
  text-align: center;
  background-color: black;
  padding: 2px 16px;
  color: white;
}

img.demo {
  opacity: 0.6;
}

.active,
.demo:hover {
  opacity: 1 !important;
}

img.hover-shadow {
  transition: 0.3s;
}

.hover-shadow:hover {
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
  cursor:pointer;
}

JSファイル(MyLightbox.js)

class MyLightbox {
  constructor(selector,options) {
    /* オプション取得 */
    this.selector = selector;
    this.slideIndex = options.slideIndex || 1;
    this.slideWidth = options.slideWidth || '45%';
    this.slideNoCapWidth = options.slideNoCapWidth || '60%';
    this.prevClass = options.prevClass || 'prev';
    this.nextClass = options.nextClass || 'next';
    this.modalClass = options.modalClass || 'modal';
    this.modalId = options.modalId || 'myModal';
    this.numbertextClass = options.numbertextClass || 'numbertext';
    this.captionClass = options.captionClass || "caption-container";
    this.captionId = options.captionId || "caption";
    this.thumbClass = options.thumbClass || 'demo';
    this.columnClass = options.columnClass || 'column';
    this.slideClass = options.slideClass || 'mySlides';
    if ( options.thumbVisible == undefined ) this.thumbVisible = true;
    else this.thumbVisible = options.thumbVisible;
    /* 初期化処理実行 */
    this.init();
  }

  /* Lightbox領域生成 */
  init() {
    var myModal = document.createElement("div");
    myModal.className = this.modalClass;
    myModal.id = this.modalId;

    var btnClose = document.createElement("span");
    btnClose.className = "close cursor";
    btnClose.innerHTML = "&times;"
    btnClose.addEventListener( 'click',  function() {
        this.closeModal();
      }.bind(this), false 
    );
    var modalContent = document.createElement("div");
    modalContent.className = "modal-content";
    if ( this.thumbVisible ) {
      modalContent.style.width = this.slideWidth;
    } else {
      modalContent.style.width = this.slideNoCapWidth;
    }
    modalContent.style.backgroundColor = "inherit"

    var slides = document.querySelectorAll(this.selector);

    if ( slides != undefined  ) {
      var nCount = slides.length;
      for ( var i=0; i < nCount; i++ ) {
        var imgObj = slides[i];
        imgObj.className = 'hover-shadow';
        /* イベント設定 */
        this.setSlideClickEvent(imgObj,i+1);
        var mySlide = document.createElement("div");
        mySlide.className = this.slideClass;

        var numberText = document.createElement("div");
        numberText.className = "numbertext";
        numberText.innerHTML =  String(i+1) + " / " + String(nCount);

        var lightboxSlide = document.createElement("img");
        lightboxSlide.src = imgObj.src;
        lightboxSlide.style.width = "100%";
        mySlide.appendChild(numberText);
        mySlide.appendChild(lightboxSlide);
        modalContent.appendChild(mySlide);
      }

      if ( nCount > 1 ) {
        var btnPrev = document.createElement("a");
        btnPrev.className = this.prevClass;
        btnPrev.innerHTML = "&#10094;";
        btnPrev.addEventListener( 'click',  function() {
            this.plusSlides(-1);
          }.bind(this), false 
        );

        var btnNext = document.createElement("a");
        btnNext.className = this.nextClass;
        btnNext.innerHTML = "&#10095";
        btnNext.addEventListener( 'click',  function() {
            this.plusSlides(1);
          }.bind(this), false 
        );
        modalContent.appendChild(btnPrev);
        modalContent.appendChild(btnNext);
      }

      var captionArea = document.createElement("div");
      captionArea.className = this.captionClass;

      var captionText = document.createElement("p");
      captionText.id = this.captionId;
      captionArea.appendChild(captionText);
      modalContent.appendChild(captionArea);

      for ( var i=0; i < nCount; i++ ) {
        var imgObj = slides[i];
        /* サムネイル作成 */
        var thumbArea = document.createElement("div");
        thumbArea.className = this.columnClass;
        thumbArea.style.width =  String((100 / nCount)) + '%';

        if ( this.thumbVisible == false ) thumbArea.style.display ='none';
        var thumbnail = document.createElement("img");
        thumbnail.src = imgObj.src;
        thumbnail.className = this.thumbClass;
        thumbnail.style.width = "100%";
        thumbnail.alt = imgObj.alt;

        thumbArea.appendChild(thumbnail);
        modalContent.appendChild(thumbArea);
        /* サムネイルクリック時のイベントを設定 */
        this.setThumbClickEvent(thumbnail,i+1);
      }
    }
    myModal.appendChild(btnClose);
    myModal.appendChild(modalContent);
    document.body.appendChild(myModal);
    this.showSlides(this.slideIndex);
  }

  // Open the Modal
  openModal() {
    document.getElementById(this.modalId).style.display = "block";
  }
  // Close the Modal
  closeModal() {
    document.getElementById(this.modalId).style.display = "none";
  }

  // Next/previous controls
  plusSlides(n) {
    this.showSlides(this.slideIndex += n);
  }
  // Thumbnail image controls
  currentSlide(n) {
    this.showSlides(this.slideIndex = n);
  }
  showSlides(n) {
    var i;
    var slides = document.getElementsByClassName(this.slideClass);
    var dots = document.getElementsByClassName(this.thumbClass);
    var captionText = document.getElementById(this.captionId);
    if (n > slides.length) {this.slideIndex = 1}
    if (n < 1) {this.slideIndex = slides.length}
    for (i = 0; i < slides.length; i++) {
      slides[i].style.display = "none";
    }
    for (i = 0; i < dots.length; i++) {
      dots[i].className = dots[i].className.replace(" active", "");
    }
    slides[this.slideIndex-1].style.display = "block";
    dots[this.slideIndex-1].className += " active";
    captionText.innerHTML = dots[this.slideIndex-1].alt;
  }
  setSlideClickEvent(slide,idx) {
    if ( slide == undefined ) return;
    /* ボタンクリック時のイベント設定 */
    slide.addEventListener( 'click',  function() {
      this.openModal();
      this.currentSlide(idx);
    }.bind(this), false );
  }
  setThumbClickEvent(thumb,idx) {
    if ( thumb == undefined ) return;
    /* ボタンクリック時のイベント設定 */
    thumb.addEventListener( 'click',  function() {
      this.currentSlide(idx);
    }.bind(this), false );
  }
}

デモ

実装方法

MyLightbox初期化

<script type="text/javascript">
 /* thumbVisible:falseにするとサムネイルが非表示 */
 var lightbox = new MyLightbox(".column img",{ thumbVisible:false } );
</script>

MyLightboxクラスというのを作成しました。

初期化パラメータの第1パラメータに、ギャラリーを設定したい画像のセレクタを指定してください。第2パラメータには、オプションを指定してください。

以上、ご参考まで