LoginSignup
8
2

【アクセシビリティ】アクセシビリティを意識したボタンの作り方

Last updated at Posted at 2023-12-04

はじめに


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

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

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

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

アクセシビリティを意識したボタンの仕様

⚪︎ ボタンとは?

ボタンは、フォームの送信、ダイアログのオープン、アクションのキャンセル、削除操作など、ユーザーがアクションやイベントをトリガーできるようにする要素です。
ただ、リンクの機能(ページ遷移、ページ内遷移等)の役割とは違います。

ボタンには、通常のボタンのほかに以下の2種類のボタンがあります。

  • トグルボタン
    • オン(押された状態)/オン(押されてない状態)の2つの状態を持つボタン
    • aria-pressedを指定することで、支援技術にトグルボタンであることが伝わる
      • ただ、オン/オフの状態がわかるラベルの場合は必要ない
  • メニューボタン
    • メニューを開くためのボタン
    • aria-haspopupmenuortrueを指定することで、支援技術にメニューボタンであることが伝わる

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

  • Spaceキー
    • アクションやイベントをアクティブにする
    • 現在のコンテキストが変わらない場合
      • → フォーカスはボタンに残る
    • 現在のコンテキストが変わった場合
      • → 最初のフォーカス可能な要素に移動する
    • ボタンがダイアログを開く場合
      • → ダイアログ内に移動する
  • Enterキー
    • アクションやイベントをアクティブにする
    • 現在のコンテキストが変わらない場合
      • → フォーカスはボタンに残る
    • 現在のコンテキストが変わった場合
      • → 最初のフォーカス可能な要素に移動する
    • ボタンがダイアログを開く場合
      • → ダイアログ内に移動する

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

  • <button>にはrole="button"の役割がある
  • ボタンには、アクセス可能なラベルが必要。
    • デフォルトは、ボタン内のテキスト
    • aria-labelaria-labelledbyで提供することはできる
  • ボタンに機能の説明がある場合、<button>aria-describedbyで説明している要素のIDを指定する
  • アクションがが利用できない時は、aria-disabled="true"を指定する
  • ボタンがトグルボタンの場合aria-pressedを指定します。
    • トグルがオンの場合 → aria-pressed="true"
    • トグルがオフの場合 → aria-pressed="false"

アクセシビリティを意識したボタンの完成形

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

アクセシビリティを意識したボタンの作り方

1. HTMLを実装する

sample.html
<div class="buttons-container">
  <button id="default-button">
    ボタン
  </button>
  <button id="toggle-button" aria-pressed="false">
    トグルボタン:OFF
  </button>
</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;
}

.buttons-container {
  background-color: rgb(128 128 128 / .3);
  border-radius: 24px;
  padding: 16px;
  position: relative;
  min-width: 300px;
  background-blend-mode: luminosity;
  backdrop-filter: blur(15px);
}

.buttons-container::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: 24px;
  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;
}

button {
  align-items: center;
  background: none;
  border: none;
  border-radius: 100px;
  color: #ffffff;
  cursor: pointer;
  display: flex;
  font-size: 16px;
  font-weight: bold;
  justify-content: center;
  padding: 8px 16px;
  width: 100%;
}

button + button {
  margin-top: 8px;
}

button:hover {
  background: radial-gradient(34.12% 136.61% at 50% 100%, rgba(94, 94, 94, 0.14) 0%, rgba(94, 94, 94, 0.00) 73.85%), radial-gradient(50% 164.29% at 50% 100%, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0.00) 60.33%), linear-gradient(0deg, rgba(94, 94, 94, 0.18) 0%, rgba(94, 94, 94, 0.18) 100%), rgba(255, 255, 255, 0.06);
  background-blend-mode: color-dodge, normal, color-dodge, lighten;
}

button[aria-pressed="true"] {
  background: linear-gradient(0deg, rgba(94, 94, 94, 0.18) 0%, rgba(94, 94, 94, 0.18) 100%), rgba(255, 255, 255, 0.07);
  background-blend-mode: color-dodge, normal;
}

button[aria-pressed="true"]:hover {
  background: radial-gradient(101.08% 100% at 50% 100%, rgba(94, 94, 94, 0.32) 0%, rgba(94, 94, 94, 0.00) 73.85%), radial-gradient(100.02% 100% at 50% 100%, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.00) 68.75%), linear-gradient(0deg, rgba(94, 94, 94, 0.18) 0%, rgba(94, 94, 94, 0.18) 100%), rgba(255, 255, 255, 0.06);
  background-blend-mode: color-dodge, normal, color-dodge, lighten;
}

3. JavaScriptを実装する

sample.js
window.addEventListener('load', function () {
  const toggleButton = document.getElementById('toggle-button');
  
  toggleButton.addEventListener('click', switchToggleButton);
})

function switchToggleButton() {
  const toggleButton = document.getElementById('toggle-button');
  const status = toggleButton.getAttribute("aria-pressed");
  
  if (status === "false") {
    toggleButton.setAttribute("aria-pressed", "true");
    toggleButton.innerText = "トグルボタン:ON";
  } else {
    toggleButton.setAttribute("aria-pressed", "false");
    toggleButton.innerText = "トグルボタン:OFF";
  }
}

まとめ

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

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

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


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

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

8
2
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
8
2