✏️

CSSだけでカルーセルを実装してみる

2024/10/31に公開

こんにちは!アルダグラムでエンジニアをしている柴田です。

はじめに

最近はCSSの進化が著しく、JavaScriptを使わずともCSSで高度なUIコンポーネントを実装できるようになってきました。特にカルーセルのようなUIもCSSだけで実現できることを知り、最新技術をキャッチアップしておきたいと感じました。

そこで今回は、CSSのscroll-snapプロパティを活用して、3種類のカルーセルを実装する方法をご紹介します。

scroll-snapプロパティの紹介

scroll-snapプロパティとは、スクロール時に要素を特定の位置でピタリと止めることができるCSSの機能です。これにより、ユーザーはスムーズかつ直感的にコンテンツを閲覧できます。

主なプロパティ

  • scroll-snap-type:
    • 要素がスクロールスナップコンテナかどうか、どの程度厳密にスナップするか、どの軸を考慮するかなどを定義するプロパティです。
      スクロールコンテナに対してスナップスクロールの軸と挙動を指定します。
    • 軸の指定: x(水平方向)、y(垂直方向)、blockinline
      • 水平方向にスナップを効かせたい時はx を指定します
      • 垂直方向にスナップを効かせたい時はy を指定します
    • 挙動の指定:
      • mandatory : スナップポイントに必ず停止
      • proximity : ユーザーのスクロール速度に応じてスナップ
  • scroll-snap-align: 子要素がスクロール領域内でどの位置にスナップするかを指定します。
    • :
      • start: コンテナの開始位置に合わせてスナップ
      • center: コンテナの中央の位置に合わせてスナップ
      • end: コンテナの終わり位置に合わせてスナップ
  • scroll-snap-stop: スナップ位置でのスクロール停止を強制するかを設定します。
    • :
      • normal:スナップ位置で停止しない (デフォルト)
      • always: ユーザーが素早くスクロールしても必ずスナップ位置で停止

CSSだけでカルーセルを実装する

では、実際にCSSだけでカルーセルを実装してみましょう。

以下、3パターンを実装します。

  • 横方向
  • 縦方向
  • 縦横方向

まずは、カルーセルの共通となるHTML構造を定義します。共通のHTMLを使って、CSSの変更だけで縦方向、横方向、縦・横両方向のカルーセルを実装します。

  • .carousel がカルーセル全体のコンテナです。
  • .carousel-item が各カルーセルのアイテムです。
<div class="carousel">
  <div class="carousel-item item1">Item 1</div>
  <div class="carousel-item item2">Item 2</div>
  <div class="carousel-item item3">Item 3</div>
  <div class="carousel-item item4">Item 4</div>
  <div class="carousel-item item5">Item 5</div>
  <div class="carousel-item item6">Item 6</div>
</div>

縦方向

縦方向にスクロールするカルーセルを実装します。

ポイントとしては、

  • .carouseloverflow-y: autoscroll-snap-type: y mandatory を指定します。これで、縦方向のスナップスクロールを有効化します。
  • scroll-snap-align: start で、スクロール時にアイテムが開始位置でスナップします。(今回は分かりやすいように、startを採用します。)
.carousel {
  display: grid;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
  /* その他のスタイル */
}

.carousel-item {
  scroll-snap-align: start;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  /* その他のスタイル */
}

縦方向へのスムーズなスクロールを実現できました。これでより直感的な操作感が得られます。
縦方向_スクロール

横方向

横方向にスクロールするカルーセルを実装します。

ポイントとしては、

  • .carouseldisplay: flexoverflow-x: auto を設定します。これにより、水平方向にスクロール可能にします。
  • scroll-snap-type: x mandatory で、水平方向のスナップスクロールを有効化します。
  • scroll-snap-align: start で、スクロール時にアイテムが開始位置でスナップになるように設定します。
.carousel {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* その他のスタイル */
}

.carousel-item {
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  /* その他のスタイル */
}

横方向も同様に、スクロールスナップも開始点をキーにスクロールできています。
横方向_スクロール

縦横方向

縦方向・横方向の両方にスクロール可能なカルーセルを実装します。

ポイントとしては、

  • .carouseloverflow: autoscroll-snap-type: both mandatory を指定し、縦横両方向のスナップスクロールを有効化します。
    さらに、display: grid を指定し、格子状にアイテムを配置します。
  • scroll-snap-align: start で、スクロール時にアイテムが開始位置でスナップします。
.carousel {
  width: 300px;
  height: 300px;
  overflow: auto;
  scroll-snap-type: both mandatory;
  scroll-behavior: smooth;
  display: grid;
  grid-template-columns: repeat(3, 300px);
  grid-template-rows: repeat(
    2,
    300px
  ); /* アイテムが6つあるため、2行の設定 */
  /* その他のスタイル */
}

.carousel-item {
  width: 300px;
  height: 300px;
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  justify-content: center;
  /* その他のスタイル */
}

縦横方向も同様に、スクロールスナップも開始点をキーにスクロールできています。
縦横方向_スクロール

実装時のTips

スクロールスナップコンテナの厳密さを定義するには

スクロールスナップの厳密さは、scroll-snap-type プロパティの挙動の指定で定義します。

  • mandatory: スナップポイントに必ずスナップします。ユーザーが速くスクロールしても、次のスナップポイントで止まります。

    例:

    .carousel {
      scroll-snap-type: x mandatory; /* 厳密にスナップする */
    }
    
  • proximity: ユーザーのスクロール操作に応じて、スナップするかどうかをブラウザが判断します。近くにスナップポイントがあればスナップしますが、強制はされません。

    例:

    .carousel {
      scroll-snap-type: x proximity; /* ユーザーの操作を優先する */
    }
    

スクロールした時に表示領域をピタッと移動するには

表示領域をピタッと移動させるためには、以下のポイントに注意します。

  • scroll-snap-align を適切に設定する: 子要素がスナップする位置を指定します。startcenterend から選択します。

    例:

    .carousel-item {
      scroll-snap-align: start;
    }
    
  • アイテムのサイズを統一する: 各アイテムの幅や高さを統一することで、スナップが均等に働きます。

    例:

    .carousel-item {
      width: 100vw;
      height: 100vh;
    }
    
  • スムーズなスクロールを有効にする: scroll-behavior: smooth; を指定すると、スナップ時の移動がスムーズになります。

    例:

    .carousel {
      scroll-behavior: smooth;
    }
    

スクロールバーの非表示したい場合

スクロールバーを非表示にしたい場合は、以下のCSSを使用します。

.carousel::-webkit-scrollbar {
  display: none;
}

実装時の注意点

アクセシビリティの考慮

scroll-snap-stop: always;を使用すると、ユーザーが意図しないスクロールを強制される場合があります。必要に応じて使用し、ユーザーがコンテンツを自由に操作できるように配慮しましょう。

参考

https://coliss.com/articles/build-websites/operation/css/usecase-of-css-scroll-snap.html#:~:text="アクセシビリティ"

コンテンツのサイズ調整

カルーセル内のアイテムが異なるサイズの場合、レイアウトが崩れる可能性があります。flex: none;widthheightを指定して、よしなに調整することをおすすめします。

最後に

今回は、CSSのscroll-snapプロパティを活用して、3種類のカルーセルを実装する方法をご紹介しました。実装前は「CSSだけでカルーセルが実現できるのか」と半信半疑でしたが、実際に試してみるとその手軽さと効果に驚かされました。

今回触れなかった部分としては、さらなるカスタマイズ、アクセシビリティの深掘り、パフォーマンスの検証などがあります。これらについては今後学んでいき、より高品質なUIを提供できるようにしていきたいです!

ここまでご覧いただきありがとうございました!

参考情報


もっとアルダグラムエンジニア組織を知りたい人、ぜひ下記の情報をチェックしてみてください!

アルダグラム Tech Blog

Discussion