ReactとTypeScriptを使用した画像比較スライダーのUI。庭のビフォーアフターを表示し、アクセシビリティ対応を強調。

正直なところ、最初は画像を並べるだけで十分だと考えていました。

しかし、実際に使ってみるとスライダーの重要性に気づきました。

ガーデン管理アプリの結果画面では、AIが生成した外構デザインのBefore/After画像を表示していました。
しかし、従来は2枚の画像を並べて表示するだけでした。

ユーザーが細かい違いを比較しにくいという課題がありました。
そこで、スライダーで重ねて比較できるインタラクティブなUIに改善することになりました。

ReactでBefore/After比較UIを実装したい方にとって、この記事は実践的なガイドとなります。

こんな人におすすめ

この記事は以下のような方に役立ちます。

  • ReactでBefore/After比較UIを実装したい方
  • react-compare-sliderの使い方を学びたい方
  • 画像比較スライダーを簡単に作成したい方
  • タッチデバイス対応・アクセシビリティ対応の実装に関心がある方
  • UIコンポーネントの設計パターンを学びたい方

目次

Before/After画像比較スライダーとは

Before/After画像比較スライダーとは、2枚の画像を重ねて表示し、スライダーをドラッグすることで比較できるインタラクティブなUIコンポーネントです。

主な特徴:

  • ドラッグ操作でBefore/Afterの境界線を移動
  • 重ねて表示することで細かい違いを比較可能
  • タッチデバイスに対応していればモバイルでも操作可能
  • 写真比較サイトや、リフォーム事例、美容施術のビフォーアフター表示などで活用されています

Reactでは、react-compare-sliderというライブラリを使うことで、この機能を簡単に実装できます。

💡 外部リンク: react-compare-slider公式ドキュメント - GitHubリポジトリで詳細なAPIリファレンスを確認できます。

要件

スライダー機能の要件を整理します。

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
    style B fill:#d1fae5
    style C fill:#fef3c7
    style D fill:#fce7f3
  • スライダーをドラッグしてBefore/Afterを重ねて比較
  • タッチデバイス対応(モバイルでの操作性確保)
  • スライダー位置の初期値は中央(50%)
  • モバイルでも操作しやすいハンドルサイズ(48px以上)
  • キーボード操作対応(アクセシビリティ)
  • 未ログイン時はスライダー操作を無効化してログイン促進

実装方針

1. ライブラリ選定: react-compare-sliderを採用

  • タッチデバイス対応が組み込み済み
  • キーボードナビゲーション対応(keyboardIncrement prop)
  • ゼロ依存で軽量
  • disabled propが組み込み済み

💡 外部リンク: Tailwind CSS v4公式ドキュメント - 本記事で使用しているTailwind CSS v4の最新情報を確認できます。

2. コンポーネント設計: ImageCompareSlider.tsxを新規作成

  • Props: beforeImage, afterImage, beforeAlt, afterAlt, initialPosition, disabled, showLabels, className
  • ハンドル: green-500色、48x48px
  • トランジション: 0.2s ease-out

3. ResultStep.tsx統合

  • 2画像レイアウト(オープン/セミクローズ外構): スライダーでBefore/After表示
  • 3画像レイアウト(クローズド外構): 外部視点をスライダー化、室内視点は別枠
  • モーダルボタン: スライダー下部に「Before拡大」「After拡大」ボタン配置

4. スタイル実装

  • @layer componentsで全スタイルをスコープ化
  • ラベル: 左上「Before」、右上「After」(半透明黒背景 + backdrop-blur)
  • disabled時オーバーレイ: ログインプロンプト表示
  • レスポンシブ対応

ポイント

react-compare-sliderのAPI活用

主要なPropsの使い方を解説します。

// Before画像コンポーネント(alt属性でアクセシビリティ対応)
<ReactCompareSliderImage
  src={beforeImage}
  alt="Before: 改修前の外構デザイン"
/>

// After画像コンポーネント(alt属性でアクセシビリティ対応)
<ReactCompareSliderImage
  src={afterImage}
  alt="After: 改修後の外構デザイン"
/>

// メインのスライダーコンポーネント
<ReactCompareSlider
  itemOne={<ReactCompareSliderImage src={beforeImage} alt={beforeAlt} />}
  itemTwo={<ReactCompareSliderImage src={afterImage} alt={afterAlt} />}
  position={initialPosition}
  disabled={disabled}
  handle={
    <ReactCompareSliderHandle
      buttonStyle={{
        backgroundColor: '#22c55e', // green-500
        width: 48,
        height: 48,
      }}
    />
  }
  keyboardIncrement="5%"
  transition="0.2s ease-out"
/>

主要なPropsを説明します。

graph LR
    A[ReactCompareSlider] --> B[itemOne]
    A --> C[itemTwo]
    A --> D[position]
    A --> E[disabled]
    A --> F[handle]
    A --> G[keyboardIncrement]
    A --> H[transition]

    B --> B1[Before画像]
    C --> C1[After画像]
    D --> D1[初期位置: 50%]
    E --> E1[操作無効化]
    F --> F1[ハンドルカスタマイズ]
    G --> G1[キーボード移動量]
    H --> H1[アニメーション]

    style A fill:#e0e7ff
    style B fill:#d1fae5
    style C fill:#fce7f3

主要な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;
  }
  /* ... */
}

💡 関連記事: next/fontでNoto Sans JPをセルフホスティングする方法 - Tailwind CSS v4との統合方法について詳しく解説しています。

アクセシビリティ対応

ライブラリ組み込みのアクセシビリティ機能を活用します。

  • ライブラリ組み込みのキーボード操作(左右矢印キー)
  • 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"

💡 外部リンク: WCAG 2.1 ガイドライン - ウェブアクセシビリティの国際標準規格について確認できます。

学び

個人的に、この実装を通じて学んだことは大きかったです。

  • ライブラリ選定の重要性: 要件に合ったライブラリを選ぶことで実装工数を大幅に削減できました。react-compare-sliderはdisabled、キーボード操作、タッチ対応が全て組み込み済みでした。

  • テストの構文エラー発見: 大規模なテストファイルでは、ブラケットの数が合っているか確認が重要です。grep -c '{' file && grep -c '}' fileで簡単にチェックできます。

  • button要素のフォーカス可能性: ネイティブの<button>要素はtabIndex属性なしでもデフォルトでフォーカス可能です。テストでtabIndex="0"をチェックするのは不適切でした。

  • Tailwind CSS v4のレイヤー: @layer componentsを使用することで、カスタムスタイルを適切なスコープに配置し、優先順位の問題を回避できます。

💡 関連記事: React Toast通知システムの実装ガイド - アクセシビリティ対応を考慮したUIコンポーネントの設計パターンについて詳しく解説しています。

よくある質問

Q1. react-compare-slider以外に、Before/After比較スライダーのライブラリはありますか?

A: はい、いくつかの選択肢があります。

ライブラリ 特徴 推奨ケース
react-compare-slider タッチ対応・アクセシビリティ対応・軽量 推奨
react-before-after-slider シンプルで使いやすい 基本的な比較のみ
react-compare-image カスタマイズ性が高い 高度なカスタマイズが必要な場合

個人的には、react-compare-sliderが最もバランスが良いと感じています。

Q2. モバイルでの動作はどうですか?

A: react-compare-sliderはタッチデバイス対応が組み込み済みなので、モバイルでもスムーズに動作します。

ただし、以下の点に注意が必要です。

  • ハンドルサイズを48px以上にする(指で操作しやすくするため)
  • ホバー時のツールチップはモバイルでは表示されない
  • touch-action: none CSSプロパティでスクロールとの競合を防ぐ

Q3. アクセシビリティ対応はどの程度実装されていますか?

A: ライブラリ側で以下のアクセシビリティ機能が実装済みです。

  • role="slider" の自動設定
  • aria-valuenowaria-valueminaria-valuemax の自動設定
  • キーボード操作(矢印キー)対応
  • aria-disabled の自動設定(disabled時)

開発者側で追加すべき対応は以下の通りです。

  • 画像のalt属性を適切に設定する
  • aria-labelでスライダーの目的を説明する
  • キーボードフォーカスが見えるようにする

Q4. 画像のサイズはどうすれば良いですか?

A: 2枚の画像は同じサイズにすることを推奨します。

  • 幅と高さが一致している画像を使用する
  • 異なるサイズの場合はCSSで調整するか、画像編集ソフトで統一する
  • 最適なパフォーマンスを得るには、画像をWebP形式で圧縮してから使用する

Q5. TypeScriptの型定義は提供されていますか?

A: はい、react-compare-sliderはTypeScriptの型定義を提供しています。

import { ReactCompareSlider, ReactCompareSliderImage } from 'react-compare-slider';

// 型定義が自動補完されます
const beforeAlt: string = "Before: 画像の説明";
const afterAlt: string = "After: 画像の説明";

まとめ

本記事では、ReactでBefore/After画像比較スライダー機能を実装する方法を解説しました。

実装のポイント

  1. react-compare-sliderを採用: タッチ対応・キーボード対応・disabled機能を一括実装
  2. Tailwind CSS v4の@layer components: スタイルをスコープ化
  3. アクセシビリティ対応: ライブラリ組み込みで実現

得られた効果

  • ユーザー体験の向上(スライダーで直感的に比較可能)
  • モバイル対応(タッチデバイスで操作可能)
  • アクセシビリティ対応(キーボード操作可能)

個人的には、このライブラリ選定で実装工数を大幅に削減できたと感じています。

要件に合ったライブラリを選ぶ重要性を教えてくれました。