改めてカルーセルを見つめ直してみる Summer 2025
https://gyazo.com/1f41d223473249bb042850413c09117a
https://gyazo.com/a6d28b60f6d8d7af63407708ad65cebf
メニューのドキュメントアイコンより「プレゼンテーションを開始」クリックでプレゼンテーションが始まります
自己紹介
yamanoku.icon @ yamanoku
katashin.icon 「Web UIの勉強会をやります」 A. yamanoku.iconが改めて見つめ直したいと思ったから
話すこと・話さないこと
話すこと
必要な要件・要素
話さないこと
言葉として定義がぶれやすい部分
今回の発表では以下の定義で進めます
表示されるもの自体は「スライド」
carrousel「カルーゼル」(フランス語)が語源 https://gyazo.com/058aae203e14b18cb054ad2de5530213
https://gyazo.com/002645ceaad9058aa2d4e6b8525b4e7a
https://gyazo.com/202fa93679b60d9cb654cd11aaba0ab4
画面幅最大のもの
などなど
最低限必要になるもの
コンテナ要素
スライドを次へ、前へ送るボタン
要件によって必要になる部分
一度に表示できる数の制御
自動送り(auto play)する
1→2→3→4→5→1...のように戻る
移動させる方向が左右か上下か
レスポンシブであるか
停止ボタン(自動送りができる場合)
指示出し:yamanoku.icon
code:prompt
Webで使われるカルーセルUIがカルーセルたるために最低限必要な要素・要件、必要に応じて使われる要素・要件、アクセシブルにするために必要な要件についてをまとめあげてください。
サンプルコードは、特定のライブラリを使用せずに、HTML、CSS、Vanilla JavaScriptかあるいはTypeScriptのみで提示してください。
一部スクリーンリーダー通知部分がなかったり、自動送りが動かないバグがあったので修正をして完成
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();
}
};
キーボード操作
カルーセル内のいずれかの要素にキーボードフォーカスが入ると、自動送りを停止するようにする 自動送りの制御ボタンは最初にフォーカスされるようにする aria-live
ライブリージョン・通知
aria-controls
スライドとそれを制御するボタンとの関係性を明示
aria-selected
現在選択されたスライドのページネーション部分
aria-roledescription
aria-roledescription=slideみたいに使う
buttonやregionとかの具体的なロール名には使わないようにする
タブUIのような形式で実装する(role=tab, tabpanel)
role=carouselの提案(Closeされている)
提案
擬似要素で表現
::scroll-marker-group、::scroll-marker
ページネーション部分
::scroll-button()
挙動はCSSアニメーション、スクロール制御などで実現
問題点
疑似要素で生成されたインタラクティブな要素(タブやボタン)は、スクリーンリーダーに正しく認識されないことがある ::scroll-markerがrole=tabになるが、対応するrole=tabpanelが不足してる
疑似要素に content プロパティでラベルを付けるが、すべてのマーカーが同じ名前になる可能性がある content: attr(aria-label)のようにする
タブキーや矢印キーでの操作が期待通りに動作しない
OpenUIでもCarousel実装を検討してるみたいだが、調査のみで特に進展はなさそう 終わりに:カルーセルを実装するにはどうしたらいいのか? 知識ゼロで1から実装するにはめちゃくちゃ大変なUIであることには変わりない
デザイナーとの協業する際はイメージが合わせやすいかも?
必要なものはなにか、必要な要件は何かを徹底的に練っていく
どこでどう使えるものかを考える
カルーセルとしてどう扱うかのOK or NGを定義しておく もしかしたら不要になるかもしれない落としどころを付ける
yamanoku.icon はちゃんとできてません(自戒) Thank you for listening !
https://gyazo.com/4c1d0df4903765cc351797c10f903ba1
参考資料