座席指定システムにおける購入導線のアクセシビリティ改善

こちらの記事は、アソビューAdvent Calendar 2023の22日目(B面)です。

はじめに

こんにちは!アソビュー株式会社でフロントエンドエンジニアをしている村井です。 先日、社内の輪読会でアクセシビリティについての本を読み、アクセシビリティとその重要性について学びました。それをきっかけとして、弊社でもアクセシビリティの改善をはじめています。 今回は開発中の座席指定システムにおける購入導線のアクセシビリティ改善について紹介します。
輪読会の詳細については、弊社の櫻井が先日投稿した記事をご覧ください。

tech.asoview.co.jp

座席指定システムとは

会場全体図や座席図などから任意の座席を選択し、チケットを購入するシステムです。

対応方針

アクセシビリティの改善を進める前に、現状で何ができていないかを確認しました。その結果、支援デバイスを利用するユーザーにとっての使い勝手が考慮されていないことがわかりました。たとえば、キーボード操作やスクリーンリーダーを使用しても、適切なフォーカス管理やアクセス可能なナビゲーションが不足している問題がありました。これらの問題は、障害を持つユーザー、効率を重視するユーザー、一時的な障害や特定の状況下で支援デバイスを使用するユーザーなど、多様なニーズに対応するために重要です。

これらのユーザーにとって、支援デバイスの操作サポートはウェブサイトやアプリケーションの使いやすさを大きく向上させます。改善前の状態では、アクセシビリティの問題だけでなく、実際の使用においても不便さを感じる点がありました。

これらの問題を解決するために、リンクやボタンとして機能すべき箇所をdiv要素から適切なHTML要素へと変更しました。これにより、さまざまな支援デバイスを使用しても、よりスムーズにナビゲーションできるようになり、操作性が向上しました。以下で、各画面での具体的な改善点を説明します。

1. 公演選択画面

本画面では公演の日付を選択します。
アコーディオン要素がdivで構成されていたため、支援デバイスで適切にフォーカスが当たらず、アコーディオンを開閉することができませんでした。
これはdiv要素をdetails要素とsummary要素に差し替えることで解決しました。

// before
return (
  <div>
    <content />
  </div>
);

// after
return (
  <details>
    <summary>contentTitle</summary>
    <content />
  </details>
);

2. エリア選択画面

本画面ではエリアを選択します。
エリアの要素をbutton要素に置き換えることで、支援デバイスでエリアを選択できるようにしました。
また、画面には会場の全体図が表示され、在庫が存在するエリアのみがハイライトされています。 マウス操作時はハイライトされたエリアをクリックすることで、そのエリアの座席選択画面に遷移します。 しかし、この全体図はmap要素で構成されており、その幅や高さは設定できません。そのため、支援デバイスでフォーカスを移動してもoutlineが表示されません。 これを解決するためにtabindexを-1に設定し、会場全体図のフォーカスをスキップしエリアコンテンツにフォーカスが当たるようにしました。

// before
return (
  <>
    <map name="Map">
      <area tabIndex={0} />
    </map>
    <div>
      <content />
    </div>
  </>
);


// after
return (
  <>
    <map name="Map">
      <area tabIndex={-1} />
    </map>
    <button>
      <content />
    </button>
  </>
);

3. 座席選択画面

本画面では座席を選択します。 座席の要素をbutton要素に置き換えることで、支援デバイスで座席を選択できるようにしました。 在庫がない場合や販売不可の席がある場合は、tabindexを-1に設定しフォーカスが当たらないようにしています。 またbutton要素にはaria-labelを設定し、'A列2番目の座席'など、座席番号を設定することで、読み上げを行えるよう改善しました。

// before
return (
  <div>
    <content />
  </div>
);

// after
const seatDetail = `${seat.column}${seat.seatNumber}番目の座席`;
return (
  <button tabIndex={isDisabled ? -1 : 0} aria-label={seatDetail}>
    <content />
  </button>
);

4. 券種選択画面

本画面はモーダルで、券種を選択します。 当初の設計では支援デバイスで操作を行うとモーダル外の要素にフォーカスが移動してしまう問題がありました。そこでフォーカストラップを実装し、モーダル内でのみフォーカスが移動するように改善しました。また、戻るボタンをbutton要素に置き換え、さらにescapeキーでモーダルを閉じられるようにしました。

// before
const handleOnClose = useCallback(() => {
  onClose?.()
}, [onClose]);

return (
  <>
    <div>戻る</div>
    <Modal onClose={handleOnClose} />
  </>
);

// after
const handleOnClose = useCallback(() => {
  onClose?.()
}, [onClose]);

useEffect(() => {
  if (!isOpen) return;
  history.pushState(null, '', location.href);
  window.addEventListener('popstate', handleOnClose);
  document.addEventListener('keydown', handleOnEscapeKeydown);
  return () => {
    window.removeEventListener('popstate', handleOnClose);
    document.removeEventListener('keydown', handleOnEscapeKeydown);
  };
}, [handleOnClose, handleOnEscapeKeydown, /* other dependencies */]);

return (
  <>
    <button>戻る</button>
    <Modal onClose={handleOnClose} />
  </>
);

※フォーカストラップの実装は長くなるため割愛します。

5. 購入画面

本画面ではチケットの購入を確定します。
画面遷移の導線をbutton要素に置き換えました。

まとめ

今回の改善により、支援デバイスでの座席購入が利用できるようになりました。 今後もユーザーが快適に操作できるようアクセシビリティの改善に向けて取り組みを続けていきたいと思います。

We're hiring!

アソビューではより良いプロダクトを世の中に届けられるよう一緒に挑戦していくエンジニアを募集しています。カジュアル面談もやっていますので、気になった方はエントリーのほどお願いいたします! www.asoview.com

speakerdeck.com

アソビュー!の技術情報を発信する公式アカウントもありますのでぜひフォローお願いします! https://twitter.com/Asoview_dev