4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コンポーネントごとに考えるアクセシビリティAdvent Calendar 2023

Day 19

【アクセシビリティ】アクセシビリティを意識したスライダーの作り方

Last updated at Posted at 2023-12-18

はじめに

みなさんアクセシビリティを意識して開発できていますか?

必要なところにrole属性を記述したり、tabキーでフォーカスができるようにしたりなど、意識しないといけないことも多いです。
そのため、アクセシビリティを完璧にやろうとするのは一苦労です。

ただ、コンポーネントごとに区切って、アクセシビリティを理解しておけば、実装するタイミングに思い出しやすく、アクセシビリティも意識しやすいと思います。

そのため、この記事では「スライダー」に焦点を当てて、アクセシビリティを意識したスライダーの実装方法とスライダーで意識した方がいいアクセシビリティを解説しようと思います。

アクセシビリティを意識したスライダーの仕様

⚪︎ スライダーとは?

スライダーは、ユーザーが与えられた範囲内から値を選択する入力方法の1つです。
スライダーは通常、バー、レール、またはトラックに沿って動かすことができるスライダーサムを持ち、それによってスライダーの値を変更します。

タッチベースの支援技術を使用するユーザーは、支援技術が提供するジェスチャーがまだ必要な出力を生成しない可能性があるため、スライダーの入力方法に困難するかもしれません。

⚪︎ キーボードインタラクション

  • →キー
    • スライダーの値を1ステップ増加させる
  • ↑キー
    • スライダーの値を1ステップ増加させる
  • ←キー
    • スライダーの値を1ステップ減少させる
  • ↓キー
    • スライダーの値を1ステップ減少させる
  • Homeキー
    • スライダーをその範囲の最初の許容値に設定する
  • Endキー
    • スライダーをその範囲の最後の許容値に設定する
  • Page Upキー(任意)
    • 上矢印によるステップ変更よりも大きい量でスライダーの値を増加させる
  • Page Downキー(任意)
    • 上矢印によるステップ変更よりも大きい量でスライダーの値を減少させる

⚪︎ WAI-ARIA の役割、状態、プロパティ

  • フォーカス可能なスライダーコントロールとして機能する要素には role="slider" を設定する
  • スライダー要素には、スライダーの現在値を表す値を aria-valuenow で設定する
  • スライダー要素には、スライダーの最小許容値を表す値を aria-valuemin で設定する
  • スライダー要素には、スライダーの最大許容値を表す値を aria-valuemax で設定する
  • aria-valuenowの値がユーザーフレンドリーでない場合、aria-valuetext で理解しやすい文字列で設定する
    • aria-valuetext="月曜日"
  • スライダーに可視ラベルがある場合、スライダー要素上のaria-labelledbyで参照される
    • そうでない場合、スライダー要素にはaria-labelによってラベルを提供する
  • スライダーが垂直方向に配置されている場合、aria-orientation="vertical" を設定する
    • スライダーは、aria-orientation="horizontal" がデフォルト値

アクセシビリティを意識したスライダーの完成形

See the Pen Meter Accessibillity by でぐぅー | Qiita (@sp_degu) on CodePen.

アクセシビリティを意識したスライダーの作り方

1. HTMLを実装する

sample.html
<div class="container">
  <input
    id="meter"
    type="range"
    aria-label="スライダー"
    min="0"
    aria-valuemin="0"
    max="10"
    aria-valuemax="10"
    value="5"
    aria-valuenow="5"
  >
  </input>
</div>

2. CSSを実装する

sample.css
body {
  background-color: #212529;
  color: #fff;
  display: grid;
  height: calc(100vh - 40px);
  margin: 0;
  padding: 20px 0;
  place-items: center;
  width: 100vw;
}

.container {
  backdrop-filter: blur(50px);
  background-color: rgb(128 128 128 / .3);
  background-blend-mode: luminosity;
  border-radius: 32px;
  max-width: 400px;
  padding: 20px;
  position: relative;
  width: 100%;
  &::before {
    background: linear-gradient(135deg, rgb(255 255 255 / .4) 0, rgb(255 255 255 / 0) 40%, rgb(255 255 255 / 0) 60%, rgb(255 255 255 / .1) 100%);
    border: 1.4px solid transparent;
    border-radius: 32px;
    content: "";
    inset: 0;
    position: absolute;
    -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0) border-box;
    -webkit-mask-composite: destination-out;
    mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0) border-box;
    mask-composite: exclude;
    z-index: -1;
  }
}

input[type="range"] {
  appearance: none;
  background: none;
  border-radius: 8px;
  display: block;
  max-width: 400px;
  overflow: hidden;
  width: 100%;
  &::-webkit-slider-runnable-track {
    background-blend-mode: color-dodge, lighten;
    height: 16px;
  }
  
  &::-webkit-slider-thumb {
    appearance: none;
    background: radial-gradient(#ffffff 6px, #ababab 6px);
    border-radius: 0 8px 8px 0;
    height: 16px;
    width: 16px;
  }
}

3. JavaScriptを実装する

sample.js
document.addEventListener('DOMContentLoaded', () => {
  const sliders = document.querySelectorAll('input[type="range"]');
  sliders.forEach((slider) => {
    slider.addEventListener('input', (e) => {
      updateSlider(e.target);
    });
    updateSlider(slider);
  });
 
  function updateSlider(slider) {
    const bc = '#242424';
    const ac = '#ababab';
    if (slider.value >= slider.max / 2) {
      const progress = (slider.value / slider.max) * 100 - 1;
      slider.style.background = `linear-gradient(to right, ${ac} ${progress}%, ${bc} ${progress}%)`;
    } else {
      const progress = (slider.value / slider.max) * 100 + 1;
      slider.style.background = `linear-gradient(to right, ${ac} ${progress}%, ${bc} ${progress}%)`;
    }
    slider.ariaValueNow = slider.value;
  }
});

まとめ

この記事では、「スライダー」に焦点を当てて、アクセシビリティを意識したスライダーの実装方法とスライダーで意識した方がいいアクセシビリティを解説しました。

ぜひこの記事をストックして、スライダーを実装する時にアクセシビリティについて思い出してもらえると嬉しいです。

Advent Calendar 2023では、他のコンポーネントにも焦点を当てて、アクセシビリティについても解説しているので、ぜひ購読していてください。


最後まで読んでくださってありがとうございます!

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?