フォームが多いアプリケーションの UX 改善
井関禎朗
はじめに
はじめまして、今年のRecruit Job for Student 2020 で Web フロントエンドエンジニアとしてアルバイトをしていた井関です。
私は 1 ヶ月のアルバイト期間で、あるプロジェクトに参画してユーザー体験 (以下 UX) を改善する取り組みを行いました。今回改善していたアプリケーションは、目的を達成するまでに入力しなければならないフォームがとても多い、正確な入力が要求される、利用者がとても多いという特徴があります。この特徴に沿って、多くのユーザーがより快適に正しく入力できるフォームを目指して様々な施策を行ったので、調査から改善までの手順や具体的な改善例を開発者の目線から紹介します。
想定読者
- UI / UX に興味がある開発者
- フォームの改善に興味がある開発者
目次
- 調査方法
- 改善のプロセス
- 実際に見つかった問題と改善例
- フォーカスとアウトライン表示
- フォームのエラー表示
- フォーム変更時にフォーカスが失われる
- 今後の展望
- まとめ
- おわりに
調査方法
まずは現状の問題点を洗い出すために調査を行いました。調査の基準は Web Content Accessibility Guidelines 2.0 (以下 WCAG 2.0) というウェブアクセシビリティの推奨事項がまとめられたものとしました。これをもとにアクセシビリティを確認するツールによる自動検証をしたり、プロダクトを実際に利用してユーザーの導線をたどったりしました。また、UX については個人的な解釈も交えて以下の項目についても注視していました。
- ユーザーの動作を減らすこと
- ユーザーの思考を減らすこと
- ユーザーのミスを減らすこと
- 一般的に用いられていること
ユーザーの導線をたどる
アクセシビリティ・UX の問題が発生するのは、ユーザーが実際にアプリケーションを利用しているときです。したがって、アクセシビリティ・UX 改善では、ユーザーの導線を整理して実際に利用して検証を行うことが大切です。検証時には初期からの開発者を交えて画面を共有して通話しながら、気になった箇所を次々に質問して、開発上避けられなかったことや過去にどんな議論があったかなどの情報を得ることができました。ブレインストーミングのようにアイデアを発散させていくことで、開発者でも気づかなかった問題も次々に発見することができました。
ツールによる自動検証
全てを手作業で検証することは大切ですが現実的ではありません。そこで、今回は @storybook/addon-a11y
を採用してコンポーネントごとにアクセシビリティの自動検証を行いました。
@storybook/addon-a11y
は UI コンポーネントをカタログのように表示できる Storybook のアドオンの 1 つで、導入するだけでアクセシビリティの問題を解析することができます。解析は Web アクセシビリティをテストするエンジンである Axe が定めているルール (WCAG 2.0 を包含) をもとに行われます。
改善のプロセス
見つかった改善点を整理した後に、どんな改善方法があるか調査・検討を行いました。その後開発のリーダーや設計をしている方に壁打ちを行い、フィードバックをいただきました。アプリケーションの使いやすさはユーザーによって異なるので、客観的な意見を取り入れながら検討することでよりよいアイデアになりました。ここまでに決まった改善案を残りの期間で実装していきました。
実際に見つかった問題と改善例
フォーカスとアウトライン表示
HTML には、 button や input のようにフォーカス可能な要素はフォーカスされたときにアウトラインが表示されるため、ユーザーは自身が操作している箇所がひと目で分かります。一方でアウトラインは、 UI デザインの都合で非表示にされることが少なくありません。今回のアプリケーションにおいて、一部の要素はアウトラインが非表示になっていたので、ユーザーの混乱を避けるために改善する必要がありました。
問題
button や input の一部がフォーカスされているのにアウトラインが表示されない。
改善例
outline: none
を解除してアウトラインが表示されるようにしました。また、これだけでは UI デザインの都合でアウトラインが非表示にされていた問題が解決されないので、what-input というライブラリを使用して、キーボード操作のときだけアウトラインを表示するようにしました。
1 2 3 4 5 6 7 8 9 |
import { css } from '@emotion/core' import 'what-input' export const globalStyle = css` [data-whatinput='mouse'] *:focus, [data-whatinput='touch'] *:focus { outline: none; } ` |
:focus-visible
(polyfill) を利用すれば同様のことができますが、今回は他の用途でも what-input を利用しているため採用は見送りました。
フォームのエラー表示
フォームによってはメールアドレスや郵便番号のように入力する形式が定められていることがあります。これらはユーザーとのコンタクトに必要な情報であり正しく入力されることが重要なので、間違った形式だとエラーを表示して再入力を求めるのが普通です。しかし、エラー表示はユーザーにストレスを与え、再入力はユーザーの動作を増やすので、極力減らすように改善を行いました。
問題
正しい形式以外で入力するとバリデーションエラーになってしまい、ユーザーが入力し直す必要がある。
改善例
システム上間違った形式でも一般的に正しい形式であれば、blur 時にフォーマットする。
郵便番号を入力するフォームが想像しやすいでしょう。郵便番号はハイフンを含む形式 (000-0000) とハイフンを含まない形式 (0000000) のどちらも間違いではありません。しかしアプリケーションによっては、ハイフンを含まない形式しか許容しないこともあります。ハイフンが含まれるときは自動的にハイフンを取り除くことで、形式の違いによるエラーそのものを取り除き、ユーザーが再入力する手間も取り除くことができます。
フォーム変更時にフォーカスが失われる
複数のフォームがあるときは、フォームの状態をまとめて配列で保存・描画することがあります。ここで注意したいのは、1 つのフォームの状態を更新したときに他のフォームも更新・再描画されてしまうという点です。再描画のタイミングで DOM の参照が失われると、フォーカスの状態も失われます。
通常は key
属性を正しく設定すると参照が失われることを防ぐことができますが、特定の条件では意図しない動作が起きてしまいます。
問題
配列の state を Array.prototype.map()
で複数のフォームとして描画するときに、1 つの state を更新しただけで全てのフォームを再描画してしまい、DOM の参照が失われるタイミングでフォーカスが失われる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import React, { memo, useMemo } from "react"; import { range } from "remeda"; import Checkbox from "./Checkbox"; const labelList = ["確認1", "確認2", "確認3", "確認4", "確認5"]; type Props = { checked: boolean[]; handlers: Array<() => void>; }; const Form: React.FC<Props> = ({ checked, handlers }) => { const CheckboxList = useMemo( () => ({ checked, handlers }: Props) => ( <> {range(0, 5).map((i) => ( <Checkbox key={i} label={labelList[i]} onChange={handlers[i]} checked={checked[i]} /> ))} </> ), [checked, handlers] ); return ( <form> <CheckboxList checked={checked} handlers={handlers} /> </form> ); }; export default memo(Form); |
改善例
上記のコードは、useMemo
の第 2 引数が変更されるたびに Fragment がアンマウントされてチェックボックスの参照が失われてしまいます。解決する方法は以下の 2 通りあります。
- Fragment を消して返り値を React.FC から Element[] にする – CodeSandBox
- useMemo の第 2 引数を修正してコンポーネントの再生成が起きないようにする – CodeSandBox
今後の展望
今回はフォームに注目した様々な UX 改善を行いましたが、いくつかやり残したことがあります。そのうちの 1 つは、改善のプラクティスを調査していたときに発見した reward early, punish late (報酬は先に、罰は後に) という考え方によるエラー表示です。
Inline validation in forms — designing the experience
これは複数のフィールドが存在するフォームにおいて、現在までに入力しているフィールドが全て valid であれば onblur
でエラー表示、1 つでも invalid なものがあれば oninput
でエラー表示を行うというものです。極力エラー表示を控えつつ、必要なユーザーに対してはエラーを表示するので UX の改善が見込めます。
また、今回の改善活動は UX やアクセシビリティという文脈全体で見ると、達成できたことはほんの一部だけでした。しかし、これをきっかけにチームや組織として改善する流れを作ることができたので、今後の活動でより多くのことが達成できることを期待しています。
おわりに
今回の 1ヶ月間のアルバイトでは UX の調査から改善まで取り組みました。普段は触れることが少ない、大規模で複雑な要件のアプリケーション開発に主体的に関われたのは、貴重な経験でした。
社会情勢を考慮して完全オンラインでの参加になりましたが、メンターさんをはじめとした方々のサポートのおかげで、不自由を感じることなく過ごせました。また、リクルートのよもやま (1on1) 文化を活かして、魅力的な社員の方々と話す時間があったのも楽しかったです。
冬アルバイトも募集中
2021年2月から3月までのアルバイトの募集が始まっています!リクルートのアルバイトでは、皆さんそれぞれのやりたいことにフォーカスして、新しいことにチャレンジすることができます。興味がある方はぜひチェックしてみてください。