画像の切り替わりを円形にカスタムしたスライダー

画面録画 2025-01-29 115053.mp4

ページ全体の雰囲気に合わせてスライダーを曲線で変化させるものに変更した。 HTMLの構成などは今までと大きな変更点はない。

今回はシンプルな構成で丸いボタン(pagination)のみにして、矢印ボタンは設置しなかった。

丸いボタンを押したときに合わせて、スライド画像と対応したボタンが切り替わるように設定するのにてこずった。

HTMLの記述

    <!-- curvy slider ここから -->
    <section class="curvy-slider">
      <div class="img-slider">
        <div class="slider">
          <div class="slide-item active">
            <img src="images/slide1_blue_eyes.jpg" alt="" />
            <div class="slide-info">
              <h2>Slide 01</h2>
              <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Excepturi, nemo!</p>
            </div>
          </div>
          <div class="slide-item">
            <img src="images/slide2_white.jpg" alt="" />
            <div class="slide-info">
              <h2>Slide 02</h2>
              <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Excepturi, nemo!</p>
            </div>
          </div>
          <div class="slide-item">
            <img src="images/slide3_hug.jpg" alt="" />
            <div class="slide-info">
              <h2>Slide 03</h2>
              <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Excepturi, nemo!</p>
            </div>
          </div>
          <div class="slide-item">
            <img src="images/slide4_home.jpg" alt="" />
            <div class="slide-info">
              <h2>Slide 04</h2>
              <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Excepturi, nemo!</p>
            </div>
          </div>
          <div class="slide-item">
            <img src="images/slide5_lookup.jpg" alt="" />
            <div class="slide-info">
              <h2>Slide 05</h2>
              <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Excepturi, nemo!</p>
            </div>
          </div>
        </div>
        <div class="navigation">
          <div class="btn active"></div>
          <div class="btn"></div>
          <div class="btn"></div>
          <div class="btn"></div>
          <div class="btn"></div>
        </div>
      </div>
    </section>

CSSの記述

仕組みの理解があいまいだったのもあり、思った通りにスライド画像の大きさや配置を設定するのに手間取った。基本的には枠のサイズを決めて、中に配置する子要素に幅と高さを%で指定しておく。

今回はレスポンシブにもある程度適応させている。

/* イメージスライダーの設定 丸く変形してスライドする
ここから -------------------------- */

.curvy-slider {
  width: 95%;
  height: 70vw;
  max-height: 700px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: radial-gradient(var(--primary-clr), var(--secondary-clr));
  border-radius: 15px;
  margin-bottom: 80px;
}

.img-slider {
  position: relative;
  /* width: 800px;
  height: 600px;
  margin: 10px 10px 50px 10px; */
  width: 85%;
  height: 85%;
  margin: 10px auto 50px;
  border-radius: 15px;
}

.img-slider .slide-item {
  z-index: 1;
  position: absolute;
  width: 100%;
  height: 100%;
  clip-path: circle(0% at 0 50%);
}

.img-slider .slide-item.active {
  clip-path: circle(150% at 0 50%);
  transition: 2s;
  transition-property: clip-path;
}

.img-slider .slide-item img {
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}

.img-slider .slide-item .slide-info {
  position: absolute;
  top: 0;
  padding: 15px 30px;
}

.img-slider .slide-item .slide-info h2 {
  color: var(--white-clr);
  font-size: 45px;
  text-transform: uppercase;
  font-weight: 800;
  letter-spacing: 2px;
}

.img-slider .slide-item .slide-info p {
  color: var(--white-clr);
  background: rgba(0, 0, 0, 0.2);
  font-size: 16px;
  width: 60%;
  padding: 10px;
  border-radius: 4px;
}

.img-slider .navigation {
  z-index: 2;
  position: absolute;
  display: flex;
  bottom: -60px;
  left: 50%;
  transform: translateX(-50%);
}

.img-slider .navigation .btn {
  background: rgba(64, 168, 196, 0.8);
  width: 20px;
  height: 20px;
  margin: 20px;
  border-radius: 50%;
  cursor: pointer;
}

.img-slider .navigation .btn:hover {
  background-color: rgba(255, 255, 255, 0.5);
}

.img-slider .navigation .btn.active {
  background: rgba(255, 201, 60, 0.7);
  box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
}

@media (max-width: 880px) {
  .img-slider .slide-item .slide-info {
    padding: 10px 25px;
  }

  .img-slider .slide-item .slide-info h2 {
    font-size: 35px;
  }

  .img-slider .slide-item .slide-info p {
    width: 70%;
    font-size: 15px;
  }

  .img-slider .navigation {
    bottom: -50px;
  }

  .img-slider .navigation .btn {
    width: 20px;
    height: 20px;
    margin: 15px;
  }
}

@media (max-width: 620px) {
  .img-slider {
    width: 400px;
    height: 250px;
  }

  .img-slider .slide-item .slide-info {
    padding: 10px 20px;
  }

  .img-slider .slide-item .slide-info h2 {
    font-size: 30px;
  }

  .img-slider .slide-item .slide-info p {
    width: 80%;
    font-size: 13px;
  }

  .img-slider .navigation {
    bottom: -50px;
  }

  .img-slider .navigation .btn {
    width: 10px;
    height: 10px;
    margin: 8px;
  }
}

@media (max-width: 420px) {
  .img-slider {
    width: 320px;
    height: 200px;
  }

  .img-slider .slide-item .slide-info {
    padding: 5px 10px;
  }

  .img-slider .slide-item .slide-info h2 {
    font-size: 25px;
  }

  .img-slider .slide-item .slide-info p {
    width: 90%;
    font-size: 11px;
  }

  .img-slider .navigation {
    bottom: -40px;
  }

  .img-slider .navigation .btn {
    width: 10px;
    height: 10px;
    margin: 6px;
  }
}
/* イメージスライダー ここまで */

JSの記述

const imgSlider = document.querySelector(".slider");
const slides = document.querySelectorAll(".slide-item");
const dots = document.querySelectorAll(".btn");
const sliderContainer = document.querySelector(".imag-slider");

let currentIndex = 0;
let autoSlideInterval;

function updateDots() {
  dots.forEach((dot, index) => {
    if (index === currentIndex) {
      dot.classList.add("active");
    } else {
      dot.classList.remove("active");
    }
  });
}

function updateSlides() {
  slides.forEach((slide, index) => {
    if (index === currentIndex) {
      slide.classList.add("active");
    } else {
      slide.classList.remove("active");
    }
  });
}

function showSlides(index) {
  if (index >= slides.length) {
    currentIndex = 0;
  } else if (index < 0) {
    currentIndex = slides.length - 1;
  } else {
    currentIndex = index;
  }
  updateSlides();
  updateDots();
}

// Function to move to the next slide
function nextSlide() {
  showSlides(currentIndex + 1);
}

// Function to move to the previous slide
function prevSlide() {
  showSlides(currentIndex - 1);
}

// Start the automatic sliding of images
function startAutoSlide() {
  autoSlideInterval = setInterval(nextSlide, 4000); // Slide every 4 seconds
}

// Stop the automatic sliding
function stopAutoSlide() {
  clearInterval(autoSlideInterval); // Clear the interval
}

// Add click event listeners to dots for direct slide navigation
dots.forEach((dot, index) => {
  dot.addEventListener("click", () => {
    stopAutoSlide(); // Stop auto-slide when manually selecting a slide
    showSlides(index); // Show the selected slide
    startAutoSlide(); // Restart auto-slide
  });
});

// Start auto-slide when the page loads
startAutoSlide();
updateDots(); // Initialize the dots

基本的な仕様としては、index番号に連動させてスライド画像とボタンの表示を切り替えていく。 切り替えの仕組みは「activeクラス」をつけたり外したりして実現している。

内部でfunctionを定義して活用していくのが非常に勉強になった。