猫の手ツール

Step 4: Quality & Design

20. 画像ツールのUI/UX設計:処理中・エラー・初期化の伝え方

画像ツールでは、利用者が今の状態と次の操作を判断できる表示が必要です。証明写真ツールのupload・loading・edit・resultを出発点に、状態の切り替えとボタンの見た目を分けて読みます。処理中、失敗からの再試行、保存までの流れを確認しましょう。

1. ノイズを極限まで削ぎ落とす「引き算」の設計

証明写真ツールを訪れるユーザーには、「履歴書を完成させたい」「至急、証明写真を用意したい」という目的があります。そんな彼らに、おしゃれな装飾や、不必要に派手なアニメーション、過度な自己主張は不要です。

最初の画面では画像選択を主な入口にし、必要な対応形式と操作説明を近くへ置きます。説明や補助操作を減らす場合も、利用者の判断に必要な情報は残します。

2. 認知負荷を下げ、「今の状態」を可視化する

「今、自分は何をすればいいのか?」という迷いは、Webツールにおいて致命的なストレスになります。状態を伝えるには、JavaScriptによる状態管理と、文言・属性・スタイルの更新を組み合わせます。Tailwind CSSは見た目の指定を助けますが、処理中かどうかを自動で管理するものではありません。

写真をえらぶ → 切り取る → 保存する。

この三段階のどこにいるかを、表示中のパネルとボタンで示します。戻る操作や失敗後の再試行も含め、利用者が次にできることと、画面の案内が一致するかを確認します。

具体的実装:状態に合わせたボタンの視覚変化

【Before】常に同じ見た目のボタン(迷いの原因)

<!-- どの段階でも同じボタンだと、次に何を押すべきか直感的に分からない -->
<button class="bg-indigo-600 text-white font-bold p-4 rounded-xl">
  処理を実行
</button>

【After】コンテキストに応じた「機能美」の実装

<!-- 
  状態管理(State)によって、次に必要なアクションだけを
  視覚的に際立たせる(ringクラスやtransitionの活用) 
-->
<button class="
  w-full py-4 rounded-[1.5rem] font-black transition-all
  active:scale-95 duration-200
  ${isReady ? 'bg-indigo-600 text-white shadow-xl ring-4 ring-indigo-100' : 'bg-slate-100 text-slate-400 cursor-not-allowed'}
">
  ${isReady ? 'このサイズで切り取る' : '写真をアップロードしてください'}
</button>

3. 注意点:過度なUXは「押し付け」になる

ユーザーを導こうとするあまり、過度なポップアップや、操作を強制するようなガードレールを敷き詰めるのは禁物です。

  • 必要な説明を操作の近くへ: 対応形式、保存方法、やり直したときに消える内容などは、短い文で示します。意味が伝わりにくいアイコンだけに頼らないようにします。
  • 待ち時間を放置しない: 処理中の説明と連続実行の防止を用意します。進捗率が測れない処理で架空の百分率を示すより、何を待っているかを伝えます。
  • やり直した場合の状態を伝える: 再編集と初期化を区別し、画像の選び直しが必要ならボタンの近くに示します。スマホのメモリを抑えるために状態を破棄する設計では、その制約を踏まえた案内が必要です。

4. 状態の切り替えと、利用者の操作を照合する

入力・処理中・編集・結果を分けると、失敗した場合にどの画面へ戻すかも決めやすくなります。

見た目を整えることに加え、利用者が画像を選び、結果を確認し、保存まで進めるかを確認します。

状態の遷移が正しいかだけでなく、表示された説明と実際にできる操作が一致しているかを確認します。

見た目と実際の操作可否を一致させる

前掲の ${isReady} を含む例は、JavaScriptで文字列を生成する場合のイメージです。そのままHTMLに置いても評価されません。また cursor-not-allowed は見た目を変えるだけで、クリックを禁止しません。実際の操作可否はdisabled属性でも更新します。

// button と status は、画面に配置したボタンとメッセージ要素
function updateReady(button, status, ready) {
  button.disabled = !ready;
  button.textContent = ready ? 'このサイズで切り取る' : '写真を選択してください';
  status.textContent = ready ? '画像を確認してから切り取れます。' : '画像はまだ選択されていません。';
}
// status にはHTML側で role="status" を指定すると更新を伝えやすい

処理開始時は二重実行を防ぎ、失敗時は再試行できる状態に戻します。成功・失敗を色だけで表さず、具体的な文言を残します。「保存できない」という場合も、画像の生成失敗と端末の保存操作を分けて案内すると、次の行動が分かりやすくなります。

証明写真の現在地は4状態、保存モードは別の状態

履歴書写真メーカーはsetUI()でupload・loading・edit・resultを切り替えます。切り抜き後は出力を作ってからresultを表示し、その結果画面でWeb用と印刷用を選べます。画面の現在地と、書き出し形式の選択は別々です。

originalCroppedCanvas = cropper.getCroppedCanvas({
  fillColor: '#ffffff', width: 600, height: 800, imageSmoothingQuality: 'high'
});
renderOutput('web');
setUI('result');

本番の切り抜き操作の抜粋です。保存モードはrenderOutput()が選択中のボタンのクラスと出力を更新します。制作解説でモードごとの寸法を確認できます。以下のdisabled・role="status"例は、操作可否と通知を学ぶ教材で、引用した本番ボタンにすべて追加済みと主張するものではありません。

まとめ

画面を簡潔にしても、利用者の判断に必要な情報まで削らないことが大切です。初回操作だけでなく、失敗から戻る操作や保存後の確認も含めて見直します。

全20回の連載にお付き合いいただき、ありがとうございました。この開発メモが、これからモダンWeb開発に挑戦する誰かの「猫の手」になれば幸いです。

参考資料

制作時に確かめたこと

ツールを作る途中で実際に確認した症状と、変更を選んだ経緯です。日付は当時の記録日です。現在の実装や、このページの学習サンプルの検証とは分けて読んでください。

AIの準備と、利用者の操作画面を混ぜない

未選択なのに編集へ進む・基本操作まで止まる

背景透過の導入中には、AIの読み込み失敗とともに画像ドロップやファイル選択が動かない状態がありました。その後は、画像を選んでいないのに選択後の画面へ進む問題も確認しています。モデルを準備するための入力と、利用者が編集する入力が、画面の状態へ同じように作用してしまうと切り分けが難しくなります。

4月6日の最終的な動作報告はありますが、途中の画面遷移を直す一つの変更だけの効果を確認した記録ではありません。さらに12日には、AIモデルや外部ライブラリの読み込み完了を待たず、メニューやモーダルを使えるようにする依頼をしています。

設計を確認する時は、ページ表示直後、モデル準備中、初期化失敗後、画像未選択、結果表示後を別々に試します。推論できることに加え、失敗しても別の説明やページへ移れるかを確認するためです。