
はじめに
正直なところ、最初は画像を並べるだけで十分だと考えていました。
しかし、実際に使ってみるとスライダーの重要性に気づきました。
Web アプリの結果画面で、AI が生成したデザイン画像の Before/After を表示していましたが、従来は2枚の画像を並べて表示するだけでした。
ユーザーが細かい違いを比較しにくいという課題があり、スライダーで重ねて比較できるインタラクティブな UI に改善することになりました。
本記事では、react-compare-slider を使った Before/After 画像比較スライダーの実装方法を、タッチデバイス対応・アクセシビリティ対応まで含めて解説します。
こんな人におすすめ
- React で Before/After 比較 UI を実装したい方
- react-compare-slider の使い方を学びたい方
- タッチデバイス対応・アクセシビリティ対応の実装に関心がある方
- UI コンポーネントの設計パターンを学びたい方
良かった点
実際にライブラリを導入してみて、一番驚いたのは実装の手軽さでした。
タッチ対応・キーボード操作・disabled 機能が全て react-compare-slider に組み込み済みで、自前で実装する必要がまったくありませんでした。
アクセシビリティ対応(role="slider" や aria-disabled)も自動で処理されるため、開発者側の実装コストが大幅に下がりました。
個人的に気に入ったのは、keyboardIncrement="5%" の一行だけでキーボード操作の移動量を設定できる点です。
ゼロ依存で軽量というのも、プロダクトに組み込む際の安心感につながりました。
Before/After 画像比較スライダーとは
Before/After 画像比較スライダーとは、2枚の画像を重ねて表示し、スライダーをドラッグすることで比較できるインタラクティブな UI コンポーネントです。
- ドラッグ操作で Before/After の境界線を移動
- 重ねて表示することで細かい違いを比較可能
- タッチデバイスに対応していればモバイルでも操作可能
- 写真比較サイトや、リフォーム事例、施術のビフォーアフター表示などで活用されています
React では、react-compare-slider というライブラリを使うことで、この機能を簡単に実装できます。
要件
スライダー機能の要件を整理します。
flowchart TD
A[Before/After比較機能] --> B[スライダー操作]
A --> C[デバイス対応]
A --> D[アクセシビリティ]
B --> B1[ドラッグで比較]
B --> B2[初期位置: 50%]
C --> C1[タッチデバイス対応]
C --> C2[ハンドルサイズ: 48px以上]
D --> D1[キーボード操作対応]
D --> D2[未ログイン時は無効化]
style A fill:#e0e7ff,stroke:#6366f1,color:#000
style B fill:#d1fae5,stroke:#10b981,color:#000
style C fill:#fef3c7,stroke:#f59e0b,color:#000
style D fill:#fce7f3,stroke:#ec4899,color:#000
- スライダーをドラッグして Before/After を重ねて比較
- タッチデバイス対応(モバイルでの操作性確保)
- スライダー位置の初期値は中央(50%)
- モバイルでも操作しやすいハンドルサイズ(48px 以上)
- キーボード操作対応(アクセシビリティ)
- 未ログイン時はスライダー操作を無効化してログイン促進
実装方針
1. ライブラリ選定: react-compare-slider を採用
- タッチデバイス対応が組み込み済み
- キーボードナビゲーション対応(
keyboardIncrementprop) - ゼロ依存で軽量
disabledprop が組み込み済み
2. コンポーネント設計: ImageCompareSlider.tsx を新規作成
- Props: beforeImage, afterImage, beforeAlt, afterAlt, initialPosition, disabled, showLabels, className
- ハンドル: green-500 色、48x48px
- トランジション: 0.2s ease-out
3. 画面統合
- 2画像レイアウト: スライダーで Before/After 表示
- 3画像レイアウト: メインビューをスライダー化、サブビューは別枠
- モーダルボタン: スライダー下部に「Before 拡大」「After 拡大」ボタン配置
4. スタイル実装
@layer componentsで全スタイルをスコープ化- ラベル: 左上「Before」、右上「After」(半透明黒背景 + backdrop-blur)
- disabled 時オーバーレイ: ログインプロンプト表示
- レスポンシブ対応
react-compare-slider の API 活用
主要な Props の使い方を解説します。
<ReactCompareSlider
itemOne={<ReactCompareSliderImage src={beforeImage} alt={beforeAlt} />}
itemTwo={<ReactCompareSliderImage src={afterImage} alt={afterAlt} />}
position={initialPosition}
disabled={disabled}
handle={
<ReactCompareSliderHandle
buttonStyle={{
backgroundColor: '#22c55e',
width: 48,
height: 48,
}}
/>
}
keyboardIncrement="5%"
transition="0.2s ease-out"
/>
主要な Props の一覧です。
| Props | 説明 | デフォルト値 |
|---|---|---|
itemOne |
Before 側の画像(左側) | 必須 |
itemTwo |
After 側の画像(右側) | 必須 |
position |
スライダー初期位置(0〜100) | 50 |
disabled |
操作を無効化するか | false |
handle |
ハンドルのカスタマイズ | デフォルトハンドル |
keyboardIncrement |
キーボード操作時の移動量 | “1%” |
transition |
アニメーション効果 | なし |
CSS スコープ化
Tailwind CSS v4 で @layer components を使用してグローバルスタイルの汚染を防止します。
@layer components {
.compare-slider-container {
@apply relative w-full max-w-4xl mx-auto rounded-lg overflow-hidden shadow-md;
}
}
ラベルの表示や disabled 時のオーバーレイも @layer components 内に閉じ込めることで、他のコンポーネントへの影響を排除できます。
アクセシビリティ対応
ライブラリ組み込みのアクセシビリティ機能を活用します。
- ライブラリ組み込みのキーボード操作(左右矢印キー)
role="slider"自動設定- disabled 時は
aria-disabled="true"が自動設定 - ボタン要素はデフォルトでフォーカス可能
sequenceDiagram
participant U as ユーザー
participant S as Slider
participant K as キーボード
Note over U,S: タッチ操作
U->>S: ドラッグ
S->>S: 位置更新
Note over U,K: キーボード操作
U->>K: 矢印キー押下
K->>S: keyboardIncrement分移動
S->>U: 位置更新
Note over U,S: disabled時
U->>S: 操作試行
S-->>U: aria-disabled="true"
開発者側で追加すべき対応は以下の通りです。
- 画像の
alt属性を適切に設定する aria-labelでスライダーの目的を説明する- キーボードフォーカスが見えるようにする
alt は「Before / After のどちらか」まで含めて書くと、読み上げでも比較の文脈が伝わります。
// Before 画像(alt に「変更前」であることを明示する)
<ReactCompareSliderImage
src={beforeImage}
alt="Before: 変更前のデザイン"
/>
// After 画像(alt に「変更後」であることを明示する)
<ReactCompareSliderImage
src={afterImage}
alt="After: 変更後のデザイン"
/>
つまづいた点
テストコードのブラケット不整合
実装の中で一番時間がかかったのはテストコードの修正でした。
大規模なテストファイルでは、ブラケットの対応が崩れていると構文エラーになりますが、どこがずれているか一見わかりませんでした。
grep -c '{' file && grep -c '}' file でブラケット数を比較することで原因を特定できました。
button 要素のフォーカス仕様
button 要素のフォーカス動作を検証しようとした際、tabIndex="0" の存在を確認するテストを書いていましたが、ネイティブの <button> 要素はデフォルトでフォーカス可能なため、そのチェック自体が不要でした。
ライブラリのデフォルト動作を過信せずに確認する習慣の大切さを学びました。
よくある質問
Q. react-compare-slider 以外の選択肢は?
いくつかの代替ライブラリがあります。
| ライブラリ | 特徴 | 推奨ケース |
|---|---|---|
| react-compare-slider | タッチ対応・アクセシビリティ対応・軽量 | 推奨 |
| react-before-after-slider | シンプルで使いやすい | 基本的な比較のみ |
| react-compare-image | カスタマイズ性が高い | 高度なカスタマイズが必要な場合 |
個人的には、react-compare-slider が最もバランスが良いと感じています。
Q. モバイルでの動作は?
react-compare-slider はタッチデバイス対応が組み込み済みなので、モバイルでもスムーズに動作します。
ハンドルサイズを 48px 以上にすること、touch-action: none CSS プロパティでスクロールとの競合を防ぐことがポイントです。
Q. 画像のサイズはどうすれば良い?
2枚の画像は同じサイズにすることを推奨します。
- 幅と高さが一致している画像を使う
- 異なるサイズの場合は CSS で調整するか、画像編集ソフトで統一する
- 表示速度を優先するなら、WebP に変換・圧縮してから使う
Q. TypeScript の型定義は?
react-compare-slider は TypeScript の型定義を提供しています。
インポートするだけで型補完が有効になります。
import { ReactCompareSlider, ReactCompareSliderImage } from 'react-compare-slider';
// 型定義が自動補完されます
const beforeAlt: string = "Before: 画像の説明";
const afterAlt: string = "After: 画像の説明";
まとめ
React で Before/After 画像比較スライダーを実装する方法を解説しました。
- react-compare-slider を採用: タッチ対応・キーボード対応・disabled 機能を一括実装
- Tailwind CSS v4 の @layer components: スタイルをスコープ化
- アクセシビリティ対応: ライブラリ組み込みで実現
個人的には、このライブラリ選定で実装工数を大幅に削減できたと感じています。
要件に合ったライブラリを選ぶ重要性を教えてくれた実装でした。


