2023.11.04
【CSS】CSSとJavaScriptで自作したカルーセル

UnsplashClaudio Testaが撮影した写真

はじめに

CSSとJavaScriptでカルーセルを作成したのでコードの紹介です。

SassやjQueryなどを使っていないので、このコードをベースに自由にカスタムしていただけるかと思います。

こんな感じのカルーセルです

ファイル構成

以下のHTML、CSS、JavaScriptをそれぞれのファイルに分け、以下の3ファイルで作成しています。

・carousel.html
・carousel.css
・carousel.js

上の3つのファイルを作成し、それぞれに以降のコードをコピペすると動きます。

carousel.html

<html>
    <head>
        <!-- CSSの読み込み -->
        <link rel="stylesheet" type="text/css" href="./carousel.css">
    </head>
    <body>



        <div class="carousel">
            <!-- 画像表示部分 -->
            <div id="items-wrapper">
                <img class="active" src="https://tekutekku.com/wp-content/uploads/2023/10/231026_1.jpg">
                <img src="https://tekutekku.com/wp-content/uploads/2023/10/231026_1.jpg">
                <img src="https://tekutekku.com/wp-content/uploads/2023/10/231026_1.jpg">
            </div>

            <!-- 画像をタブで切り替えるボタン -->
            <div id="select-tabs">
                <button class="active" onclick="changeToSelectItem(0)"></button>
                <button onclick="changeToSelectItem(1)"></button>
                <button onclick="changeToSelectItem(2)"></button>
            </div>
            
            <!-- 隣の画像に移動するボタン -->
            <div id="change-buttons">
                <button onclick="changeToPrevItem()"></button>
                <button onclick="changeToNextItem()"></button>
            </div>
        </div>

        <!-- JavaScriptの読み込み -->
        <script src="./carousel.js"></script>



    </body>
</html>

carousel.css

  /* カルーセル/////////////////////////// */
  .carousel{
    margin: 0 auto;
    --carousel-width: 420px;
    --carousel-height: 240px;
    width: var(--carousel-width);
    height: var(--carousel-height);
    position: relative;
  }


  /* items----------------------------------- */
  .carousel #items-wrapper{
    margin: 0 auto;
    width: calc(var(--carousel-width) - 100px);
    height: var(--carousel-height);
    position: relative;
    overflow: hidden;
  }
  .carousel #items-wrapper img{
    width: 100%;
    position: absolute;
    top: 20%;
    left: 0;
    opacity: 0;
  }
  .carousel #items-wrapper img.active{
    opacity: 1;
  }
  .carousel #items-wrapper img.fadeRightIn{
    animation-name: fadeRightIn;
    animation-duration: 1s;
    opacity: 1;
  }
  .carousel #items-wrapper img.fadeLeftOut{
    animation-name: fadeLeftOut;
    animation-duration: 1s;
  }
  .carousel #items-wrapper img.fadeLeftIn{
    animation-name: fadeLeftIn;
    animation-duration: 1s;
    opacity: 1;
  }
  .carousel #items-wrapper img.fadeRightOut{
    animation-name: fadeRightOut;
    animation-duration: 1s;
  }
  @keyframes fadeRightIn {
    0% {
      opacity: 0;
      transform: translateX(100%); 
    }      
    100% { 
      opacity: 1;
      transform: translateX(0%); 
    }
  }
  @keyframes fadeLeftOut{
    0% {
      opacity: 1;
      transform: translateX(0%);
    }
    100% {
      opacity: 0;
      transform: translateX(-100%);
    }
  }
  @keyframes fadeLeftIn {
    0% { 
      opacity: 0;
      transform: translateX(-100%); 
    }      
    100% { 
      opacity: 1;
      transform: translateX(0%); 
    }
  }
  @keyframes fadeRightOut{
    0% {
      opacity: 1;
      transform: translateX(0%);
    }
    100% {
      opacity: 0;
      transform: translateX(100%);
    }
  }


  /* select-tabs----------------------------- */
  #select-tabs{
    width: var(--carousel-width);
    text-align: center;
    position: absolute;
    top: 90%;
    left: 0;
  }
  #select-tabs button{
      margin: 0 3px;
      width: 20px;
      height: 20px;
      background-color: #ccc;
      border-radius: 50%;
      border: none;
      cursor: pointer;
  }
  #select-tabs button.active{
    background-color: #888;
  }


  /* change-buttons-------------------------- */
  #change-buttons{
    width: var(--carousel-width);
    display: flex;
    justify-content: space-between;
    position: absolute;
    top: 45%;
    left: 0;
  }
  #change-buttons button{
    width: 36px;
    height: 36px;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    position: relative;
    --arrow-size: 10px;
    --arrow-design: 3px solid black;
    --arrow-rotate: -45deg;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  /* 前へボタン */
  #change-buttons button:nth-child(1)::after{
    content: "";
    width: var(--arrow-size);
    height: var(--arrow-size);
    display: block;
    border-top: var(--arrow-design);
    border-left: var(--arrow-design);
    transform: rotate(var(--arrow-rotate));
  }
  /* 次へボタン */
  #change-buttons button:nth-child(2)::after{
    content: "";
    width: var(--arrow-size);
    height: var(--arrow-size);
    display: block;
    border-bottom: var(--arrow-design);
    border-right: var(--arrow-design);
    transform: rotate(var(--arrow-rotate));
  }


carousel.js

//itemを自動で切り替える間隔(ミリ秒で指定)
let intervalTime = 3000;


//////////////////////////////////////////////////////////////////////////////////
// ↓↓ 以降のコードは触らない ↓↓ //////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////



//事前準備
let itemElements = document.getElementById('items-wrapper'); //以降の処理で使いまわすので事前に要素を取得しておく
let tabElements = document.getElementById('select-tabs');    //以降の処理で使いまわすので事前に要素を取得しておく
let itemNum = itemElements.childElementCount - 1;  //インデックスは0スタートなので、取得した要素数から1引く
let activeNum = 0;  //アクティブなitemの番号を格納
let intervalId = setInterval(changeToNextItem, intervalTime); //itemの自動切り替え



//■以降の処理で使いまわす関数

//select-tab,change-buttonが押された時に、自動切り替えのタイマーをリセットする
function resetInterval(){
    clearInterval(intervalId);
    intervalId = setInterval(changeToNextItem, intervalTime);
}

//itemの切り替えに伴うtabの切り替え処理
function changeActiveTab(fromActiveNum, toActiveNum){
    fromTab = tabElements.children[fromActiveNum];
    fromTab.classList.remove('active');

    toTab = tabElements.children[toActiveNum];
    toTab.classList.add('active');
}



// select-tabsでのitemの切り替え処理 ---------------------------
function changeToSelectItem(i){
    resetInterval();
    
    fromActiveNum = activeNum;
    toActiveNum = i;

    //アクティブなitemが選択されたら何もせず処理を終了する
    if(fromActiveNum == toActiveNum){return;}

    fromItem = itemElements.children[fromActiveNum];
    fromItem.classList.remove('active');
    fromItem.classList.remove('fadeRightIn');
    fromItem.classList.remove('fadeLeftIn');
    toItem = itemElements.children[toActiveNum];
    toItem.classList.remove('fadeLeftOut');
    toItem.classList.remove('fadeRightOut');
    if(activeNum < toActiveNum){
        //次のスライドへ移動する時
        fromItem.classList.add('fadeLeftOut')
        toItem.classList.add('fadeRightIn');
    }else{
        //前のスライドへ移動する時
        fromItem.classList.add('fadeRightOut')
        toItem.classList.add('fadeLeftIn');
    }

    changeActiveTab(fromActiveNum, toActiveNum)

    activeNum = toActiveNum;
}


// change-buttonでのitemの切り替え処理 ---------------------
function changeToPrevItem(){
    resetInterval();
    
    fromActiveNum = activeNum;

    fromItem = itemElements.children[activeNum];
    fromItem.classList.remove('active');
    fromItem.classList.remove('fadeRightIn');
    fromItem.classList.remove('fadeLeftIn');

    if(activeNum == 0){
        activeNum = itemNum;
    }else{
        --activeNum;
    }

    toActiveNum = activeNum;

    toItem = itemElements.children[activeNum];
    toItem.classList.remove('fadeLeftOut');
    toItem.classList.remove('fadeRightOut');

    fromItem.classList.add('fadeRightOut')
    toItem.classList.add('fadeLeftIn');
    toItem.classList.add('active');

    changeActiveTab(fromActiveNum, toActiveNum)
}
function changeToNextItem(){
    resetInterval();
    
    fromActiveNum = activeNum;

    fromItem = itemElements.children[activeNum];
    fromItem.classList.remove('active');
    fromItem.classList.remove('fadeRightIn');
    fromItem.classList.remove('fadeLeftIn');

    if(activeNum == itemNum){
        activeNum = 0;
    }else{
        ++activeNum;
    }
    
    toActiveNum = activeNum;

    toItem = itemElements.children[activeNum];
    toItem.classList.remove('fadeLeftOut');
    toItem.classList.remove('fadeRightOut');

    fromItem.classList.add('fadeLeftOut')
    toItem.classList.add('fadeRightIn');
    toItem.classList.add('active');

    changeActiveTab(fromActiveNum, toActiveNum)
}