改めてカルーセルを見つめ直してみる Summer 2025
https://gyazo.com/1f41d223473249bb042850413c09117a
この資料は Web UI 実装勉強会 #1 のLT資料です。
https://gyazo.com/a6d28b60f6d8d7af63407708ad65cebf
メニューのドキュメントアイコンより「プレゼンテーションを開始」クリックでプレゼンテーションが始まります
自己紹介
yamanoku.icon @ yamanoku
大山奥人, おおやまみちのく a.k.a やまのく
X(旧Twitter)
GitHub
会社員
既婚で一児の父と猫🐈🐈🐈と犬🐶の飼い主
フロントエンドカンファレンス北海道2025 現地参加勢
katashin.icon 「Web UIの勉強会をやります」
yamanoku.icon おお
最初は聴者として参加予定
LT枠も空いていたのでLTで登壇してみることに
Q. 令和の現在なぜカルーセルを見つめ直す必要が?
A. yamanoku.iconが改めて見つめ直したいと思ったから
Web UI実装としては避けては通れないものの1つ
懇親会で思う所ある方はお話ししましょう!
CodeGridでは2023年に語り合ってました
開発者と考えるカルーセルUI | 第1回 カルーセルUIの現状と機能
hashrockさんも昨日ライブ実装していました(タイムリー)
@hashedrock: 久々に開発作業配信します
カルーセルUIを作ろう https://www.youtube.com/live/DHCvVvswAJE @YouTubeより
話すこと・話さないこと
話すこと
カルーセルをWeb UIとして実装してみて分かったこと
必要な要件・要素
アクセシブルにするために必要なこと
最新技術での解決策について
話さないこと
カルーセルの適切な用途について
カルーセルに対する批判
カルーセルが本当に必要かどうかについて
Should I Use A Carousel?
カルーセル?スライダー?カルーセルスライダー?
言葉として定義がぶれやすい部分
今回の発表では以下の定義で進めます
カルーセル
今回取り上げるUIの部分
表示されるもの自体は「スライド」
スライダー
type=rangeのようなUI
ちなみにカルーセルってどういう意味の言葉?
carrousel「カルーゼル」(フランス語)が語源
メリーゴーランド
回転木馬
回転式コンベア
カルーセルとしての見た目(一例)
スライドが1つもの
https://gyazo.com/058aae203e14b18cb054ad2de5530213
前後のスライドが見えるもの
https://gyazo.com/002645ceaad9058aa2d4e6b8525b4e7a
スライドが複数見えているもの
https://gyazo.com/202fa93679b60d9cb654cd11aaba0ab4
画面幅最大のもの
ヒーローイメージと兼ねている
などなど
カルーセルにUIとして求められる要件ってなんだっけ?
最低限必要になるもの
表示するスライド部分
スライドを前後に送る要素
コンテナ要素
スライドを次へ、前へ送るボタン
スワイプも可能かどうか
要件によって必要になる部分
ページネーション
一度に表示できる数の制御
自動送り(auto play)する
ループできるか
1→2→3→4→5→1...のように戻る
移動させる方向が左右か上下か
レスポンシブであるか
アクセシビリティ要件として必要
停止ボタン(自動送りができる場合)
キーボード操作が可能
フォーカストラップの制御ができる
スクリーンリーダーへの通知
ライブリージョン
AIと一緒にカルーセルを作ってみた
指示出し:yamanoku.icon
作ってくれたLLM:Gemini 2.5 Pro
https://codepen.io/yamanoku/full/EaVerzO
プロンプト例
code:prompt
Webで使われるカルーセルUIがカルーセルたるために最低限必要な要素・要件、必要に応じて使われる要素・要件、アクセシブルにするために必要な要件についてをまとめあげてください。
サンプルコードは、特定のライブラリを使用せずに、HTML、CSS、Vanilla JavaScriptかあるいはTypeScriptのみで提示してください。
一部スクリーンリーダー通知部分がなかったり、自動送りが動かないバグがあったので修正をして完成
カルーセルの内容:HTML
カルーセルの見た目:CSS
カルーセルの内部実装:TypeScript
DOM操作をするためHTMLの内容を取得してくるようにする
スライドを前後に送る要素の実装
code:typescript
const slides = Array.from(element.querySelectorAll<HTMLLIElement>('.slide'));
const slideCount = slides.length;
let currentIndex = 0;
const goToSlide = (index: number): void => {
currentIndex = (index + slideCount) % slideCount;
updateCarousel(); //スライドの移動,通知の更新,ページネーション部分の更新などを含む関数
};
const nextSlide = (): void => {
goToSlide(currentIndex + 1);
};
const prevSlide = (): void => {
goToSlide(currentIndex - 1);
};
自動送り・停止の実装
code:typescript
let intervalId: number | null = null;
const intervalTime: number = 5000; // 5 seconds
let isPlaying: boolean = true;
const stopAutoplay = (): void => {
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
};
const startAutoplay = (): void => {
stopAutoplay();
intervalId = window.setInterval(() => nextSlide(), intervalTime);
};
const restartAutoplay = (): void => {
stopAutoplay();
if (isPlaying) {
startAutoplay();
}
};
ユーザーによる停止
code:typescript
let isManuallyPaused: boolean = false; // ユーザーによる明示的な停止状態を管理
const togglePlayPause = (): void => {
if (isPlaying) {
isManuallyPaused = true;
pause();
} else {
isManuallyPaused = false;
play();
}
};
アクセシブルなカルーセルパターン
Carousel (Slide Show or Image Rotator) Pattern | APG | WAI | W3C
キーボード操作
カルーセル内のいずれかの要素にキーボードフォーカスが入ると、自動送りを停止するようにする
自動送りの制御ボタンは最初にフォーカスされるようにする
WAI-ARIA
aria-live
ライブリージョン・通知
aria-controls
スライドとそれを制御するボタンとの関係性を明示
aria-selected
現在選択されたスライドのページネーション部分
aria-roledescription
roleの具体的な説明をするWAI-ARIA
aria-roledescription=slideみたいに使う
buttonやregionとかの具体的なロール名には使わないようにする
タブUIのような形式で実装する(role=tab, tabpanel)
Time to add a new role=carousel to the ARIA spec? · Issue #1617 · w3c/aria · GitHub
role=carouselの提案(Closeされている)
実装を簡略化していく取り組み:CSSのみでのCarousel
JavaScriptの処理をCSSへ移行するモチベーション
提案
csswg-drafts/css-overflow-5/carousel-explainer.md · w3c/csswg-drafts · GitHub
擬似要素で表現
::scroll-marker-group、::scroll-marker
ページネーション部分
::scroll-button()
left, rightなどのディレクティブな値を指定
スクリーンリーダーもそれに合った呼び方をしてくれる
挙動はCSSアニメーション、スクロール制御などで実現
CSS によるカルーセルの作成 - CSS: カスケーディングスタイルシート | MDN
MDN側にも作り方を載せてる
問題点
まだクロスブラウザ対応されてない
BaselineもLimited
Are 'CSS Carousels' accessible?
CSSでのカルーセルにおけるアクセシビリティ上の問題
疑似要素で生成されたインタラクティブな要素(タブやボタン)は、スクリーンリーダーに正しく認識されないことがある
::scroll-markerがrole=tabになるが、対応するrole=tabpanelが不足してる
疑似要素に content プロパティでラベルを付けるが、すべてのマーカーが同じ名前になる可能性がある
content: attr(aria-label)のようにする
タブキーや矢印キーでの操作が期待通りに動作しない
OpenUIでもCarousel実装を検討してるみたいだが、調査のみで特に進展はなさそう
https://open-ui.org/components/carousel.research/
終わりに:カルーセルを実装するにはどうしたらいいのか?
知識ゼロで1から実装するにはめちゃくちゃ大変なUIであることには変わりない
各フレームワーク対応のライブラリを使う
UIフレームワークに載せて使うものを選ぶ
Web Componentsとして扱えるものを選ぶ
Embla Carouselが有力?
https://www.embla-carousel.com/
LLMと壁打ちしてより理想に近いカルーセルを作る
デザイナーとの協業する際はイメージが合わせやすいかも?
必要なものはなにか、必要な要件は何かを徹底的に練っていく
カルーセルを使わないで済む方法を検討する
どこでどう使えるものかを考える
カルーセルとしてどう扱うかのOK or NGを定義しておく
もしかしたら不要になるかもしれない落としどころを付ける
実装コストが~、アクセシビリティ的に~だけではなく、非実装者でも納得できる
yamanoku.icon はちゃんとできてません(自戒)
Thank you for listening !
https://gyazo.com/4c1d0df4903765cc351797c10f903ba1
参考資料
Carousels | Brad Frost
Carousel Usability: Designing an Effective UI for Websites with Content Overload - NN/G
Carousel Gallery
Creating CSS carousels
Carousels Tutorial | Web Accessibility Initiative (WAI) | W3C
カルーセルに関するおすすめの方法 | Articles | web.dev
About Carousels and ARIA Tabs – Web Axe
カルーセル | Accessible & Usable
カルーセルUIのベストプラクティス!知っておきたい基本と注意点を徹底解説 |UI/UXデザイン会社のSOLUS
みんなが使えるカルーセルUIを考える | CyberAgent Developers Blog