Zenn
🖼️

CSSのみでカルーセルを実装してみる(Chrome 135以降)

2025/03/23に公開

カルーセルといえばJavaScriptやライブラリを使うのが一般的かと思いますが、
Google Chrome 135以降では、CSSのみでカルーセルを実装できるようになりました。
https://developer.chrome.com/blog/carousels-with-css?hl=ja
どのように実装するのか、試してみました!

完成したページ

対応ブラウザ:Google Chrome 135以降
キーボードでの操作(←/→)も可能です
https://carousels-with-css.vercel.app/

使用技術

Astro(5.5.4) + microCMS + Vercel

microCMSでデータを用意する

画像データの管理にmicroCMSを使用します。
先日のアップデートで画像に代替テキストが設定できるようになったので、その動作確認もあわせてしてみたいと思います。
https://blog.microcms.io/media-alt-settings/

microCMSのAPIスキーマ設定

以下のようにmicroCMSのAPIスキーマを設定していきます。
使用するコンテンツAPIは一点のみ(オブジェクト形式)です。

コンテンツ

エンドポイント: carousel
APIの型: オブジェクト形式

フィールド ID 表示名 種類
items アイテム 複数画像

画像を登録

編集画面
画像はWhiskで生成してみました

メディア詳細画面
各画像に代替テキストを設定しておきます

APIプレビュー

APIをプレビューしてみると、以下が返ってくることが確認できました。altの値も入っています👏

{
    "createdAt": "2025-03-22T13:23:42.301Z",
    "updatedAt": "2025-03-22T13:23:42.301Z",
    "publishedAt": "2025-03-22T13:23:42.301Z",
    "revisedAt": "2025-03-22T13:23:42.301Z",
    "items": [
        {
            "url": "https://images.microcms-assets.io/assets/72395720f6d54c6580be06fdb6c5fc43/1356d207cdc04b94b310ff0e43fd94fe/whisk_storyboard67a1542702f8406c9b04dd00fb1437.png",
            "height": 384,
            "width": 704,
            "alt": "カプセルトイ"
        },
        {
            "url": "https://images.microcms-assets.io/assets/72395720f6d54c6580be06fdb6c5fc43/bd5972aed0a54c4591c9282548cdb7ea/whisk_storyboardf2b01a184e7d47c48962f579d2ecd9.png",
            "height": 384,
            "width": 704,
            "alt": "ダイナーにいるクマ"
        },
        {
            "url": "https://images.microcms-assets.io/assets/72395720f6d54c6580be06fdb6c5fc43/7a24f27a6589490dba7b0a426c04ecec/whisk_storyboard893ab09a77b24487a6430b56a0004f.png",
            "height": 384,
            "width": 704,
            "alt": "ドット絵の電話"
        },
        {
            "url": "https://images.microcms-assets.io/assets/72395720f6d54c6580be06fdb6c5fc43/288c3149516d43a49a54640046ca36af/whisk_storyboard646fb75774fe462ea64441c51fce74.png",
            "height": 384,
            "width": 704,
            "alt": "メタルな魚"
        },
        {
            "url": "https://images.microcms-assets.io/assets/72395720f6d54c6580be06fdb6c5fc43/5a02b55d846f40c594d0d47afc3b49c2/whisk_storyboard6ec66c7c5a754cfe9e2cead247d840.png",
            "height": 384,
            "width": 704,
            "alt": "海沿いでアクセサリーを作っている女の子"
        }
    ]
}

実装

Astroでプロジェクトを作成し、microcms-js-sdksassをインストールしておきます。

SDKの利用準備と型定義を行います。

src/libs/microcms.ts
import type {
  MicroCMSImage,
} from 'microcms-js-sdk';
import { createClient } from 'microcms-js-sdk';

export const client = createClient({
  serviceDomain: import.meta.env.MICROCMS_SERVICE_DOMAIN,
  apiKey: import.meta.env.MICROCMS_API_KEY,
});

export type Carousel = {
  items: MicroCMSImage[];
};

microCMSからデータを取得し、表示させています。

src/pages/index.astro
---
import Layout from '../layouts/Layout.astro';
import { client, type Carousel } from "../libs/microcms";

const data = await client.getObject<Carousel>({
  endpoint: "carousel",
});

const items = data.items ?? [];
---

<Layout>
  <div class="carousel-wrapper">
    <div class="carousel-container">
      <ul class="carousel" aria-label="Image carousel">
        {items.map((img, index) => (
          <li id={`slide${index}`} class="carousel-slide">
            <img src={img.url} alt={img.alt ?? `Slide ${index + 1}`} class="carousel-image" />
          </li>
        ))}
      </ul>
    </div>
  </div>
</Layout>

<style lang="scss">
  .carousel-wrapper {
    display: grid;
    grid-template-areas:
      "carousel"
      "markers";
    justify-content: center;
    gap: 1rem;
    padding: 2rem 1rem;
  }

  .carousel-container {
    grid-area: carousel;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    max-width: 44rem;
    margin: 0 auto;
    border-radius: 8px;
    background-color: #f8f8f8;

    scroll-marker-group: before;

    &::scroll-marker-group {
      grid-area: markers;
      display: grid;
      place-content: center;
      grid-auto-flow: column;
      gap: 0.75rem;
      padding: 0.75rem;
      scroll-padding: 1rem;
      overflow-x: auto;
      scroll-snap-type: x mandatory;
      scrollbar-width: none;
    }
  }

  .carousel {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 100%;
    scroll-padding-inline: 1rem;
    gap: 1rem;
    padding: 1rem 0;
    margin: 0;

    .carousel-slide {
      scroll-snap-align: center;
      list-style: none;
      padding: 0 1rem;

      &::scroll-marker {
        content: "";
        width: 0.75rem;
        height: 0.75rem;
        background: #bbb;
        border-radius: 50%;
        scroll-snap-align: center;
        transition: background 0.3s, border 0.3s;

        &:is(:hover, :focus-visible) {
          background: #888;
        }

        &:target-current {
          background: #91a7ff;
        }
      }
    }
  }

  .carousel-image {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    border: 2px solid #ccc;
  }
  </style>

CSSの解説

動作の流れ

  1. scroll-marker-group: before.carousel-containerに指定
  2. .carousel-containerに、::scroll-marker-groupが自動で生成される
  3. .carousel > liに、::scroll-markerが自動で作成される

scroll-marker-group

scroll-marker-groupは、スクロール位置を示すマーカー(いわゆるインジケーター)をCSSだけで生成できる仕組みです。
従来はJavaScriptでスライド番号を管理したり、手動でインジケーターを作成して切り替えたりしていましたが、これをCSSだけで自動生成してくれます。

.carousel-container {
  scroll-marker-group: before;
}
  • scroll-marker-group: before; は「この要素の前にマーカー領域を作る」という指定です
  • 自動的に::scroll-marker-groupという領域を作り、そこにマーカーを並べてくれます

::scroll-marker-group

scroll-marker-groupを指定した要素には、::scroll-marker-groupという領域が作られます。

.carousel-container::scroll-marker-group {
  grid-area: markers;
  display: grid;
  place-content: center;
  grid-auto-flow: column;
  gap: 0.75rem;
  padding: 0.75rem;
  scroll-padding: 1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
  • マーカーの表示位置や並べ方は、::scroll-marker-groupに対してCSSを当てることで調整できます
  • display: gridを使うとドットを横一列に並べることができます

::scroll-marker

::scroll-markerは、上記のscroll-marker-groupによって生成されます。

.carousel-slide::scroll-marker {
  content: "";
  width: 0.75rem;
  height: 0.75rem;
  background: #bbb;
  border-radius: 50%;
  scroll-snap-align: center;
  transition: background 0.3s, border 0.3s;
}
  • <li>要素に対して、自動で::scroll-markerが追加されます
  • スライドの数に応じて、マーカーも同じ数だけ表示されます

:target-current

現在表示されているスライドに対応するマーカーに付与されます。

.carousel-slide::scroll-marker:target-current {
  background: #91a7ff;
}

おわりに

CSSのみで完結するカルーセルを、AstroとmicroCMSを使って実装しました。
他のブラウザでも実装されると、カルーセルの実装がだいぶ楽になりそうです🙌

参考URL

https://chrome.dev/carousel-configurator/
https://nerdy.dev/css-carousel-in-chrome-135

Discussion

ログインするとコメントできます