CSSカルーセルを試す
CSS Overflow Module Level 5では、CSS のみでカルーセルを実装できる次の機能が定義されています。
- Scroll Buttons:カルーセルのスクロール領域を 85%スクロールさせるボタンを提供する。
- Scroll Markers:特定のカルーセルのアイテムまでスクロールするアンカーを提供する。
Chrome 135では、これらの機能が他のブラウザに先行して実装されました。Chrome 公式によるCSS カルーセルの解説記事も公開されています。この記事では、基本的な説明を多少は行いつつ、実装例をいくつか紹介します。
今までの CSS カルーセル
スクロールボタンやスクロールマーカーが存在しないカルーセルは、スライダーやスライドショーと呼ばれることが多いですが、次のようなカルーセルであれば以前から CSS のみで実装が出来ました。
このカルーセルは、スクロールバーまたはキーボードの矢印キーで操作することが出来ます。 また、中途半端な位置で止まらずに、ちょうど良い位置で止まるようになっています。 これは、比較的新しいscroll-snap-typeやscroll-snap-alignプロパティによるものです。
実装は、次のようになっています。
<ul class="carousel"> <li class="item"><img src="" /></li> <li class="item">...</li> ...</ul>
.carousel { display: grid; grid-auto-flow: column; grid-auto-columns: 300px; gap: 8px; overflow-x: auto; scroll-snap-type: x mandatory; > .item { scroll-snap-align: center; }}
また内部リンクを利用することで JavaScript を利用せずにスクロールマーカーを配置することも出来ました。
次のように実装できます。
<ul class="carousel"> <li class="item" id="item-1"><img src="" /></li> <li class="item" id="item-2">...</li> ...</ul><div class="scroll-markers"> <a href="#item-1">1</a> <a href="#item-2">2</a> ...</div>
スクロールボタンを配置する
スクロールボタンは、::scroll-button()
疑似要素に有効なcontent
プロパティを指定することで配置できます。
::scroll-button()
は、scroll-button(right)
やscroll-button(left)
のように指定することで左右のボタンのスタイルや位置を調整することも出来ます。またright
やleft
の代わりにinline-start
やinline-end
を指定することで、テキストの方向に応じてボタンの位置を調整することも可能です。
::scroll-button()
によるスクロールボタンを押すとスクロール領域の 85%をスクロールするため、デフォルトでは中途半端な位置でスクロールが止まります。
スクロールボタンを配置する実装は、次のようになります。
.carousel { &::scroll-button(inline-start) { content: "⬅" / "Scroll left"; } &::scroll-button(inline-end) { content: "⮕" / "Scroll right"; } &::scroll-button(*) { inline-size: 48px; aspect-ratio: 1; cursor: pointer; }}
100%のスクロールを行う
スクロールボタンを押すと、デフォルトではスクロール領域の 85%をページングします。
ですがsroll-snap-type
とscroll-snap-align
を利用すれば、次のように 100%のスクロールを実現することができます。
実装は次のようになります。
.carousel { scroll-snap-type: x mandatory; > .item { scroll-snap-align: start; }}
ボタンの位置を調整する
現状::scroll-button
は親要素によるレイアウトシステムが直接適用されないため、ボタンの配置には工夫が必要です。
配置方法としては次のような方法が考えられます。
- Grid area を利用する
- カルーセル要素のさらに親要素に
position: relative
を指定してposition: absolute
などでボタンを配置する - Anchor Positioning を利用する
Grid area はやりたいことに対して記述量が多く、position
による方法は余計な要素を追加しなければいけないため、個人的にはおすすめしません。一方、Anchor Positioning は理解さえすれば、シンプルな記述で縦横無尽にボタンを配置できるため、個人的にはおすすめです。サポートしている環境は少ないですが、CSS Overflow Module Level 5 も同様なので問題ではないでしょう。
これは、Anchor Positioning を利用して次のように実装できます。
.carousel { anchor-name: --carousel;
&::scroll-button(inline-start) { content: "⬅" / "Scroll left"; position-area: center span-end; } &::scroll-button(inline-end) { content: "⮕" / "Scroll right"; position-area: center span-start; } &::scroll-button(*) { position: fixed; position-anchor: --carousel; }}
スクロールマーカーを配置する
スクロールマーカーは、::scroll-marker-group
疑似要素と::scroll-marker
疑似要素に加えてscroll-marker-group
プロパティを指定することで配置できます。
次のように実装できます。
.carousel { scroll-marker-group: after; &::scroll-marker-group { display: grid; grid-auto-flow: column; justify-content: center; gap: 8px; margin-block-end: 48px; } > .item { &::scroll-marker { content: ""; inline-size: 24px; aspect-ratio: 1; border: 1px solid #252525; border-radius: 1e3px; } &::scroll-marker:hover, &::scroll-marker:focus-visible { background-color: #555; } &::scroll-marker:target-current { background-color: #252525; } }}
少し実装が複雑なので、各機能の軽く説明をしておきます。
scroll-marker-group
:マーカーの親要素の配置位置を指定するためのプロパティです。値はnone
、before
、after
の 3 つです。デフォルトがnone
のため、指定しないと何も表示されません。::scroll-marker-group
:複数のマーカーの親要素です。主にマーカーの配置方法や余白を調整するために利用されるでしょう。縦方向にマーカーを配置するようなことも出来ます。::scroll-marker
:個々のマーカー要素です。これはカルーセル要素ではなくカルーセルのアイテム要素に紐づいているため、例えばアイテム毎に見た目を変えたり表示させないといったことも出来ます。:target-current
:アンカー要素がアクティブである(現在表示されている)ことを表します。::scroll-maker
と組み合わせることで現在表示されているスライドのマーカーを強調出来ます。この機能もCSS Overflow Module Level 5一部であり、Chrome 135 でサポートされました。
マーカーに番号を入れる
マーカーに番号を入れるには、::scroll-marker
のcontent
プロパティに番号を入れるだけです。
counter
関数を利用すれば、簡単に実装出来ます。
次のように実装できます。
.carousel { counter-reset: count; > .item { counter-increment: count; &::scroll-marker { content: counter(count); } }}
まとめ
ここまでに紹介したスクロールボタンとスクロールマーカーを組み合わせると、次のようなカルーセルを実装できます。
CSS のみで、ここまで多機能なカルーセルを実装できるのは革新的です。 ただし、現在は Chrome 135 以降しかサポートしておらず、実験的なフェーズであるため利用には注意が必要です。