フォーム・入力

スライダー

解説あり

Slider

値を範囲から選ぶ。aria-valuenow/min/max とキーボード操作。

スライダーとは?

スライダーは、つまみを左右(または上下)に動かして、 ある範囲の中から1つの値を選ぶ UI です。音量・明るさ・再生位置などでよく使われます。

ポイントは、「いまの値」「動かせる範囲(最小・最大)」を、目で見えない人にも伝えること、 そしてマウスだけでなくキーボードでも操作できることです。

なぜアクセシビリティが大事なの?

この両方を一番カンタンに満たすのが、ネイティブの<input type="range"> です。キーボード操作も読み上げも、ブラウザが用意してくれます。

ライブデモ(推奨実装)

下はネイティブの <input type="range"> です。マウスを使わず、フォーカスして矢印キーで動かしてみてください。

アクセシブルなスライダー(ネイティブ range)
40

試してみよう:Tab でつまみへ → ← → で1ずつ、Home / End で最小・最大、Page Up / Page Down で大きく動く。

ポイント

スクリーンリーダーでつまみにフォーカスすると「音量, スライダー, 40, 最小 0, 最大 100」のように、役割・現在値・範囲がまとめて読み上げられます。すべてネイティブ要素が自動で提供します。

キーボード操作

キー動作必須/任意
/ 値を1ステップ増やす必須
/ 値を1ステップ減らす必須
Home最小値にする必須
End最大値にする必須
Page Up / Page Down値を大きいステップで増減する任意(推奨)

補足

上のキー操作は、<input type="range"> を使えばすべて自動で手に入ります。 自作(role="slider")する場合は、これらを keydown で自前実装する必要があります。

必要な WAI-ARIA / ロール

付ける場所属性 / ロール意味
ネイティブ range<label for> で関連付けつまみに名前(ラベル)を与える。これだけで role・値・範囲は自動。
自作のつまみrole="slider"「スライダーである」と支援技術へ伝える。
自作のつまみtabindex="0"div をキーボードでフォーカス可能にする。
自作のつまみaria-valuemin / aria-valuemax動かせる範囲(最小・最大)。
自作のつまみaria-valuenow現在値。動かすたびに必ず更新する。
自作のつまみaria-valuetext数値だけでは意味が伝わらないとき(「40%」「中」など)に人にわかる表現を補う(任意)。
自作のつまみaria-label / aria-labelledbyつまみの名前。可視ラベルがあれば aria-labelledby で結ぶ。

実装:推奨パターン(Good)

良い例 / 推奨

まずは <input type="range">label を結ぶだけで、role・値・範囲・キーボード操作がすべて揃います。

マークアップ:

<label for="volume">音量</label>
<input
  type="range"
  id="volume"
  name="volume"
  min="0"
  max="100"
  step="1"
  value="40" />
<output for="volume" id="volume-out">40</output>

表示の同期(任意。読み上げは input 自身が担う):

const input = document.getElementById('volume');
const out = document.getElementById('volume-out');

// 値が変わるたびに output へ反映(表示用。読み上げは input が担う)
input.addEventListener('input', () => {
  out.textContent = input.value;
});

デザイン上どうしてもネイティブが使えないときだけ、role="slider" で自作します。 その場合は値と範囲、キーボード操作をすべて自前で用意します。

<!-- ネイティブが使えない見た目要件のときだけ自作する -->
<span id="bright-label">明るさ</span>
<div
  role="slider"
  tabindex="0"
  aria-labelledby="bright-label"
  aria-valuemin="0"
  aria-valuemax="100"
  aria-valuenow="40"
  aria-valuetext="40%"
  class="slider"
  id="bright-slider">
  <span class="slider-thumb"></span>
</div>
const slider = document.getElementById('bright-slider');
const MIN = 0, MAX = 100, STEP = 1, BIG = 10;

function setValue(next) {
  const v = Math.min(MAX, Math.max(MIN, next));
  slider.setAttribute('aria-valuenow', String(v));
  slider.setAttribute('aria-valuetext', v + '%'); // 人にわかる単位を補う
  slider.style.setProperty('--pos', ((v - MIN) / (MAX - MIN)) * 100 + '%');
}

slider.addEventListener('keydown', (e) => {
  const now = Number(slider.getAttribute('aria-valuenow'));
  let next = now;
  switch (e.key) {
    case 'ArrowRight': case 'ArrowUp':   next = now + STEP; break;
    case 'ArrowLeft':  case 'ArrowDown': next = now - STEP; break;
    case 'PageUp':   next = now + BIG; break;
    case 'PageDown': next = now - BIG; break;
    case 'Home': next = MIN; break;
    case 'End':  next = MAX; break;
    default: return; // 関係ないキーは素通り
  }
  e.preventDefault();
  setValue(next);
});

アンチパターン(Bad)

下は <div> をマウスでドラッグするだけのスライダーです。マウスでは動きますが、キーボードでは一切操作できず、値も読み上げられません。

div をドラッグするだけの壊れたスライダー
明るさ

試してみよう:Tab を押してもつまみにフォーカスできません。矢印キーも効かず、スクリーンリーダーでは「スライダー」とも現在値とも分かりません。

<!-- ❌ アンチパターン:div をドラッグするだけ -->
<div class="track" onmousedown="startDrag(event)">
  <div class="knob" id="knob"></div>
</div>
<!--
  role も tabindex もないのでフォーカスできず、
  キーボードでは一切動かせない。
  aria-valuenow も無いので、いまの値が読み上げられない。
-->

悪い例 / 避ける

この実装の問題点:

  • キーボードで操作できないdiv はフォーカスを受け取れず、矢印キーで動かせない。
  • 役割が伝わらないrole="slider" が無く、スライダーだと認識されない。
  • 値・範囲が伝わらないaria-valuenow / valuemin / valuemax が無く、いま何%かも分からない。
  • 名前が無い — 何を調整するスライダーなのか(明るさ?)が伝わらない。

実装チェックリスト


原文(英語):Slider Pattern — W3C APG(新しいタブで開きます)