📷

【Rails & JavaScript】メイン画像のスライドショー

2023/07/28に公開

スライドショー作成

メイン画像がスライドショーになるように実装する。

JavaScriptの実装準備は以下に記載。
https://zenn.dev/ganmo3/articles/c01ce76c09ae8d

実装編

以下の通り実装していく。

HTML

app/views/public/homes/top.html.erb
<div class="slideshow-container">
  <div class="slide fade">
    <%= image_tag "top/top1.jpg" %>
  </div>
  <div class="slide fade">
    <%= image_tag "top/top2.jpg" %>
  </div>
  <div class="slide fade">
    <%= image_tag "top/top3.jpg" %>
  </div>
  <div class="slide fade">
    <%= image_tag "top/top4.jpg" %>
  </div>
</div>
:
:

解説

  • <div class="slideshow-container"></div>
    スライドショー全体の枠組み。

  • <div class="slide fade"></div>
    slideクラスで各スライドのスタイルを定義できるようにし、fadeクラスはスライドのフェードイン・フェードアウトの動作するためにJavaScriptで使用する。

  • <%= image_tag "top/top1.jpg" %>
    スライドショーにしたい画像をimage_tagで挿入。画像はapp/assets/imagesに格納する。

CSS

app/assets/stylesheets/public/homes.scss
.slideshow-container {
  width: 100%;
  height: 800px;
  overflow: hidden;
  position: relative;
}

.slide {
  width: 100%;
  height: 800px;
 object-fit: contain;
  position: absolute;
}

.slide img {
  width: inherit;
  height: inherit;
  margin: 0;
  padding: 0;
  border: none;
}

.slide.fade:first-child {
  opacity: 1;
}

.backimage .text {
  position: absolute;
  top: 50%;
  left: 60%;
  transform: translate(-50%, -50%);
  text-align: center;
}

.backimage .text .guidance {
  font-size: 18px;
  color: #fff;
  background-color: rgba(255, 192, 203, 0.7);
  padding: 20px;
  border-radius: 10px;
}

解説

以下の通り解説する。

  1. .slideshow-container
.slideshow-container {
  width: 100%;
  height: 800px;
  overflow: hidden;
  position: relative;
}

スライドショー全体のコンテナ(.slideshow-container)に適用させる。

  • overflow: hidden; :コンテナ外の要素が表示されないようにするために設定。
  • position: relative; :要素の位置を他の要素に対して相対的に調整する。
    今回はスライドショーをページ内のコンテンツの一部として表示したい(スライドショーがべーじ内で静止して表示し、ページがスクロールすると一緒に動く)ため、スライドショーの親であるコンテナをrelativeにし子の各スライドをabsoluteにしてあげる。
    relativeとabsoluteの使い方は以下が参考になった。
    https://zero-plus.io/media/css-position-absolute/
  1. .slide
.slide {
  width: 100%;
  height: 800px;
 object-fit: contain;
  position: absolute;
}

各スライド(.slide)に適用させる。

  • object-fit: contain;:画像がスライド内に収まるように表示されるように設定。
  • position: absolute;:スライドがコンテナ内で絶対位置になるように設定。
  1. .slide imgセレクタのスタイル:
.slide img {
  width: inherit;
  height: inherit;
  margin: 0;
  padding: 0;
  border: none;
}

各スライド内の画像(.slide img)に適用させる。

  • width: inherit;height: inherit;
    画像が親要素(スライド)の幅と高さに合わせて表示されるように設定。
  • margin: 0;padding: 0;border: none;
    余白や枠線をなくす。
  1. .slide.fade:first-child
.slide.fade:first-child {
  opacity: 1;
}

最初のスライド(.slide.fade:first-child)に適用させる。

  • opacity: 1;
    最初のスライドがフェードインで表示されるように設定。後続のスライドにはフェードアウトの効果を適用することでスライドショーとなる。
  1. その他のスタイル:
.backimage .logo {
  /* スタイルの定義 */
}

.backimage .text {
  /* スタイルの定義 */
}

.backimage .text .guidance {
  /* スタイルの定義 */
}

これらのセレクタは、背景イメージ(.backimage)内のロゴ(.logo)やテキスト(.text)およびガイダンス(.guidance)に適用させるため状況に応じて設定する。

JavaScript

app/javacript/script.js
  let slideIndex = 0;
  showSlides();

  function showSlides() {
    // スライドの要素を取得
    const slides = document.querySelectorAll(".slide.fade");
    
    // slideIndexを1増やす(次のスライドに進む)
    slideIndex++;
    
    // スライドの数よりもslideIndexが大きくなった場合、最初のスライドに戻る
    if (slideIndex > slides.length) {
      slideIndex = 1;
    }
    
    // 現在のスライドを表示(opacityを1に設定)
    slides[slideIndex - 1].style.opacity = "1";
    
    // 1つ前のスライドを非表示(opacityを0に設定)
    slides[slideIndex - 2 < 0 ? slides.length - 1 : slideIndex - 2].style.opacity = "0";
    
    // 一定時間(6000ミリ秒=6秒)後に再度showSlides関数を呼び出す(次のスライドに進むための処理)
    setTimeout(showSlides, 6000); 
  }

解説

  1. let slideIndex = 0;
    slideIndexという変数を定義し、初期値を0に設定。slideIndexは現在表示しているスライドのインデックスを表す。

  2. showSlides();
    showSlides関数を呼び出す。これにより、スライドショーが自動的に始まる。

  3. function showSlides() { ... }
    showSlidesという関数を定義。この関数内にスライドショーの動作を記載する。

  4. const slides = document.querySelectorAll(".slide.fade");
    document.querySelectorAll() メソッドを使用して、クラス名が "slide" かつ "fade" の要素を全て取得。これにより、スライドショー内の全てのスライド要素が取得される。

  5. slideIndex++;
    slideIndexを1増やす。これにより、次のスライドに進むことができる。

  6. if (slideIndex > slides.length) { slideIndex = 1; }
    もしslideIndexがスライドの数を超えた場合、最初のスライドに戻る。これにより、ループ再生になる。

  7. slides[slideIndex - 1].style.opacity = "1";
    現在のスライドを表示す。 slides[slideIndex - 1] は現在のスライド要素を表し、style.opacity プロパティに "1" を設定することで、スライドが不透明になり表示される。

  8. slides[slideIndex - 2 < 0 ? slides.length - 1 : slideIndex - 2].style.opacity = "0";
    一つ前のスライドを非表示にする。 slides[slideIndex - 2] は一つ前のスライド要素を表し、style.opacity プロパティに "0" を設定することで、スライドが透明になり非表示になる。ただし、slideIndex - 2 が0未満になる場合(最初のスライドの前)、slides.length - 1 を指定して最後のスライドに戻るようにしている。

  9. setTimeout(showSlides, 6000);
    一定時間(6000ミリ秒=6秒)後に再度showSlides関数を呼び出す。これにより、スライドが自動的に切り替わり、スライドショーが繰り返し再生される。

Discussion