コンテンツがコンテナの高さ・幅を超えた時に、スクロールで閲覧できるようにするUIコンポーネント。ブラウザネイティブの overflow: auto/scroll と、デザインに統合されたカスタムスクロールバーの2種類がある。サイドバー・チャット・コードブロック・テーブルなど、コンテンツ量が不定な領域で広く使われる。
この記事を読むと、カスタムスクロールバー vs ネイティブスクロールバーの使い分け・overflow: auto vs overflow: scroll の違い・スクロール位置の保持・キーボードスクロールのアクセシビリティ対応が自分でできるようになります。
1. UI例(Preview / Live)
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
コンテンツがコンテナの境界を超えた時に、スクロールで閲覧できる領域を作るUIコンポーネント。CSSの overflow プロパティで実装するシンプルなものから、shadcn/ui の ScrollArea のようにカスタムスクロールバーを持つものまで幅広い。
overflow の使い分け:
| 値 | スクロールバー表示 | 使い所 |
|---|---|---|
auto | コンテンツが溢れた時だけ | 推奨。多くのケースで使う |
scroll | 常時表示 | スクロールバーの有無でレイアウトが変わると困る場合 |
hidden | 非表示(スクロール不可) | 意図的にはみ出しを隠したい場合 |
clip | 非表示(スクロール不可・JS制御なし) | パフォーマンス最適化 |
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- サイドバー:ナビゲーション項目が多くなった時の縦スクロール
- チャット・メッセージ履歴:新メッセージで最下部にスクロール
- コードブロック:横方向に長いコードの横スクロール
- カードの横並びリスト:モバイルでの横スクロールカルーセル
- ドロップダウンの選択肢リスト:選択肢が多い時の縦スクロール
3.2 When NOT to use
- ページ全体のスクロール:ブラウザネイティブのスクロールに任せる(
overflow: hiddenをbodyに設定しない) - コンテンツが常に収まる場合:不要な
overflow: scrollで常時スクロールバーを表示しない
4. 設計判断の核(Decision Principles)
Scroll Areaの核は「スクロールの存在をユーザーに知らせること」——コンテンツが隠れていることに気づかないと、ユーザーは情報を見逃す。
判断の優先順位:① overflow: auto vs scroll の選択 → ② スクロール可能であることの視覚的ヒント → ③ キーボードアクセシビリティ → ④ スクロール位置の保持
overflow: autoを基本とする:overflow: scrollは常にスクロールバーを表示してレイアウトに影響する。overflow: autoはコンテンツが溢れた時だけスクロールバーを表示するため、ほとんどのケースでautoが正しい選択- 横スクロール領域には「続きがある」ことを示す:横スクロールは縦スクロールと異なりユーザーが気づきにくい。右端にグラデーションフェード、またはシャドウを付けることで「右にコンテンツが続く」ことを視覚的に示す
tabIndex={0}でキーボードスクロールを有効にする:スクロール可能な要素がフォーカス可能でないと、キーボードユーザーが矢印キー・PageUp/PageDown でスクロールできない。tabIndex={0}を付与して必ずキーボードでもスクロールできるようにする- チャットは最新メッセージを常に最下部に表示する:
useEffectで新メッセージが追加された時にscrollIntoView({ behavior: 'smooth' })を呼び出すか、scrollTop = scrollHeightを設定して最下部を維持する
5. 状態設計(States)
| 状態 | 表示 |
|---|---|
| コンテンツが収まる | スクロールバーなし(overflow: auto の場合) |
| コンテンツが溢れる | スクロールバー表示 |
| スクロール中 | ホバー時スクロールバー強調(カスタムの場合) |
| 最上部 / 最下部 | フェードで端を示す |
6. バリエーション設計(Variants)
| バリアント | 方向 | 使用例 |
|---|---|---|
| 縦スクロール | overflow-y: auto | サイドバー・リスト・チャット |
| 横スクロール | overflow-x: auto | テーブル・カード列・コードブロック |
| 縦横両方 | overflow: auto | コードエディター・地図・キャンバス |
| カスタムスクロールバー | @radix-ui/react-scroll-area | デザイン統一が必要なサイドバー・パネル |
ネイティブ vs カスタムの判断:
- モバイル → ネイティブ一択(iOS/AndroidのモメンタムスクロールはCSSで再現が難しい)
- デスクトップ、デザイン統一が重要な場面 → カスタム(shadcn/ui の
ScrollArea) - シンプルなオーバーフロー制御 →
overflow: auto+ CSS のみ
7. パターン集(Good / Bad / How to fix)
7.0 よく崩れる設計パターン(3つ)
overflow: hiddenを親要素に設定してスクロールを完全に封じる:コンテンツが見えなくなり、ユーザーが情報を取得できない(特にモーダル外の body に設定する場合は注意)- 横スクロール領域に視覚的ヒントがない:ユーザーが横にコンテンツが続くことに気づかず、情報を見逃す
tabIndexなしのスクロール領域:キーボードユーザーがその領域にフォーカスできず、矢印キーでスクロールできない
7.1 Bad(典型3つ)
overflow: scrollを使い、コンテンツが収まっていても常にスクロールバーが表示されてレイアウトが崩れる- 横スクロール可能なテーブルに何も視覚的ヒントがなく、右側のカラムがあることに気づかれない
<div style="overflow: auto; height: 200px">にtabIndexがなく、Tabキーでフォーカスできない
7.2 Good(対になる3つ)
overflow-y: autoでコンテンツが溢れた時だけスクロールバーを表示する- 横スクロール領域の右端に
background: linear-gradient(to right, transparent, white)のフェードを重ねて「続きがある」ことを示す <div role="region" aria-label="..." tabIndex={0}>でキーボードフォーカスとスクリーンリーダーへの伝達を両立する
7.3 How to fix(手順)
overflow: scrollをoverflow: autoに変更する- スクロール可能な要素に
tabIndex={0}を追加する role="region"+aria-label="[コンテンツの説明]"を付与する- 横スクロール領域に右端フェードのグラデーションを追加する(CSS
::after疑似要素または絶対配置のdiv)
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Keyboard
Tabでスクロール領域にフォーカス↑/↓/←/→でスクロールPageUp/PageDownでページ単位スクロールHome/Endで先頭 / 末尾にジャンプ
Screen Reader
<!-- 縦スクロール領域 -->
<div
role="region"
aria-label="通知一覧"
tabIndex="0"
style="overflow-y: auto; height: 300px;"
>
<!-- コンテンツ -->
</div>
<!-- チャット履歴 -->
<div
role="log"
aria-label="チャット履歴"
aria-live="polite"
tabIndex="0"
style="overflow-y: auto;"
>
<!-- メッセージ -->
</div>
チャット・メッセージ履歴には role="log" + aria-live="polite" を使う。通常のスクロール領域には role="region" を使う。
10. 実装メモ(Implementation Notes)
- shadcn/ui の
ScrollAreaは@radix-ui/react-scroll-areaベース。OSのスクロールバーを非表示にして、カスタムスクロールバーをCSSで描画するため、WindowsとmacOSで見た目が統一される - ネイティブスクロールバーのスタイルをCSSだけで変更したい場合は
::-webkit-scrollbar(Chromium系)を使えるが、Firefox はscrollbar-colorとscrollbar-widthを使う。クロスブラウザ対応には両方の記述が必要 - スクロール位置の保持(ページ遷移後に元の位置に戻る)は
sessionStorageにスクロール位置を保存し、ページ復帰時にscrollTopを復元する実装が一般的
11. 関連リンク
- 関連するUIデザイン原則: 情報密度 (Information Density), スキャンしやすさ (Scannability)
- 用語集(定義): レスポンシブデザイン (Responsive Design)
- 関連するUIコンポーネント(横): Resizable(リサイザブル), Sidebar(サイドバー), Table(テーブル), Responsive Patterns(レスポンシブパターン)
12. まとめ
Scroll Areaの設計で最重要なのは「スクロールの存在をユーザーに知らせること」と「キーボードアクセシビリティ」です。迷ったら 4. 設計判断の核 に戻り、「overflow: auto を使っているか」「tabIndex={0} があるか」「横スクロール領域に視覚的ヒントがあるか」の3点を確認してください。ネイティブスクロールかカスタムスクロールかの選択は、モバイルファーストならネイティブ、デスクトップでデザインの統一が重要ならカスタムという基準で判断します。