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

## はじめに
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/c87447be-a905-1a6e-2ecd-eec839d8f2dc.png)

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

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

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

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

## アクセシビリティを意識したメーターの仕様
### ⚪︎ メーターとは？
メーターは、定義された範囲内で変動する数値をグラフィカルに表示するコンポーネントです。
そのため、バッテリー残量や車の燃料レベルを示すために使用されます。

ただ、以下のような場合は使うべきではありません。

+ 最大値がないような値を示すためには使うべきではない
+ ローディングやタスク完了パーセンテージなどの進行状況を示すためには使うべきではない

### ⚪︎ キーボードインタラクション
特になし

### ⚪︎ WAI-ARIA の役割、状態、プロパティ
+ メーターとして機能する要素には `role="meter"` を設定する
+ メーターではメーターの現在値を表すために `aria-valuemin` と `aria-valuemax` の間の値を `aria-valuenow` に設定する
+ メーターには、`aria-valuemax` より小さい値を `aria-valuemin` に設定する
+ メーターには、`aria-valuemin` より大きい値を `aria-valuemax` に設定する
+ 支援技術では、よく `aria-valuenow` をパーセンテージとして提示される
  + メーターの値をパーセンテージで伝えることがユーザーフレンドリーでない場合、`aria-valuetext` でメーターの値を理解しやすくする文字列を設定する
  + 例）バッテリーメーター `aria-valuetext="50%（残り6時間）"`
+ メーターに可視ラベルがある場合、`role="meter"` を持つ要素のIDを `aria-labelledby` に設定する
  + そうでない場合、`role="meter"` を持つ要素に `aria-label` を設定する

## アクセシビリティを意識したメーターの完成形
<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="WNPyOqR" data-editable="true" data-user="sp_degu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/WNPyOqR">
  Meter Accessibillity</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## アクセシビリティを意識したメーターの作り方
### 1. HTMLを実装する
```sample.html
<div class="container">
  <meter
    id="meter"
    aria-label="メーター"
    min="0"
    aria-valuemin="0"
    max="100"
    aria-valuemax="100"
    value="5"
    aria-valuenow="50"
  >
  </meter>
</div>
```

### ２. 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;
  }
}

meter {
  width: 100%;
  max-width: 400px;
  
   &::-webkit-meter-bar {
    background: linear-gradient(0deg, rgba(94, 94, 94, 0.13) 0%, rgba(94, 94, 94, 0.13) 100%), rgba(255, 255, 255, 0.07);
    background-blend-mode: color-dodge, lighten;
    height: 4px;
    border: none;
  }

  &::-webkit-meter-optimum-value,
  &::-webkit-meter-suboptimum-value,
  &::-webkit-meter-even-less-good-value {
    background: rgba(255, 255, 255, 0.60);
    border-radius: 2px;
  }
}
```

### 3. JavaScriptを実装する
```sample.js
const container = document.getElementById('meter');
let value = 1;
let boolean = true

function setValue () {
  timer1 = setInterval(() => {
    roundValue = value % 90 + 5;
    container.value = roundValue;
    container.ariaValueNow = roundValue;
    
    if (boolean) {
      ++value;
    } else {
      --value;
    }
    
    if (value === 90) {
      boolean = false;
    } else if (value === 1) {
      boolean = true;
    }
  }, 10);
}

window.addEventListener('load', function(){
  setValue();
});
```

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

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

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

https://qiita.com/advent-calendar/2023/degudegu2510

---

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

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

https://twitter.com/degudegu2510