states について
states は、データに依存するインターフェースの設計と実装を支援するスキルです。読み込み、空、部分表示、エラー、オフライン、成功の各状態に加え、遷移、再試行、楽観的更新、未保存データの扱いを説明します。
主な機能
- 01データ領域ごとの状態の列挙
- 02スケルトンと読み込み時間の設計
- 03空状態と検索結果なしの区別
- 04エラー、再試行、古いデータへの対応
- 05楽観的更新と未保存内容の指針
- 06状態間の視覚的な遷移の計画
活用シーン
- 01初回読み込みや更新中のページ設計
- 02空の領域や検索結果なしの UI 作成
- 03エラー時やオフライン時のデータ表示計画
- 04保存失敗、楽観的更新、未保存変更への対応
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ paragonhq/ stealth-skills --skill statesインストール後、Claude Code で/statesを入力して読み込まれたか確認します。
詳細
状態
快適に進むケースは6つの状態のうちの1つです。インターフェースは残りの5つで評価されます。そこで人々は行き詰まり、待ち、不安を感じているからです。
実装前に洗い出す
データに依存する各領域について、次のリストを作成します。
| 状態 | 条件 | 表示内容 |
|---|---|---|
| 初回読み込み | まだデータがない | 最終レイアウトに合わせたスケルトン |
| 再読み込み | データがあり、更新中 | データはそのまま表示し、控えめなインジケーターを表示 |
| 空 | リクエストは成功したが、表示するものがない | 1行と1つのアクション |
| 一部表示 | データの一部、または1ページ分がある | ある分を表示し、明確な境界を示す |
| エラー | リクエストに失敗した | 起きたこと、次にすること、再試行 |
| 古いデータ/オフライン | データが古い可能性がある | データを表示し、古いことを明示 |
| 成功 | アクションが完了した | その場で、目立たないように表示 |
このうち2つしか扱っていない領域は、未完成です。
読み込み中
スケルトン
- 最終レイアウトに正確に合わせます。高さと幅(無理のない範囲で)を同じにし、リズムも揃えます。形の異なるコンテンツに置き換わるスケルトンは、スピナーよりも悪い印象を与えます。
- スペースを確保します。コンテンツが表示されても、ページ上の要素が動かないようにします。
- 要素の角丸に合わせた、
--hoverレベルのグレーのブロックを使います。シマーは使わないか、振幅を抑えたゆっくりとした2〜2.5秒のパルスにします。速いシマーは待ち時間を長く感じさせます。 - スケルトンの行数は3〜5行にします。画面全体を埋める必要はありません。ユーザーに必要なのは形であり、数ではありません。
- コンテンツにはスケルトンを使います。アクションにはスピナーを使います。
タイミング
- 最初の150〜200msは読み込み状態を表示しません。多くのリクエストはその間に完了し、ちらつきは何も表示しないよりも悪いためです。
- 一度表示したら、ちらつきを防ぐために少なくとも300msは表示します。
- 3秒を超えたら、「処理中です…」や進捗の見積もりを表示します。
- 10秒を超えたら、抜け出す方法を用意します。キャンセル、または「完了したら通知します」を提示します。
再取得
すでにデータがある場合、スケルトンに置き換えることは絶対に避けます。データはそのまま表示し、領域の近くに小さなインジケーター(ヘッダーの薄いスピナーや控えめなバー)を表示して更新を示すか、更新が速い場合は何も表示しません。データが消えてから再び現れることは、画面が壊れたように感じられる最も一般的な原因です。
画像
バイトデータが届く前に表示領域を確保できるよう、widthとheight(またはaspect-ratio)を指定します。読み込み時は200msかけてフェードインさせます。画面下部の画像にはloading="lazy"を指定します。読み込みに失敗した場合は、壊れた画像アイコンではなく、同じサイズの目立たないプレースホルダーを表示します。
空
空の状態は、オンボーディングの機会です。次の要素を含めます。
- ここに何が表示されるかを伝える1行(「プロジェクトはまだありません」など)。
- ここに表示するものを作成する1つのアクション(「プロジェクトを作成」など)。プライマリボタンとしてスタイルを設定します。
- 任意で、それが重要な理由や、どのように表示されるようになるかを説明する1行。
説明対象の領域内に、その領域のサイズに合わせて表示します。ページ全体を覆ってはいけません。プロダクトにイラストのシステムがない限り、イラストは使いません。単独の宇宙飛行士のクリップアートは、テンプレートのように見えてしまいます。
空の状態と、フィルター適用後に何も表示されない状態を区別します。「fooの検索結果はありません。フィルターをクリア」という状態は、「プロジェクトはまだありません」とは異なります。
一部表示
- ページネーションがある場合は、境界を示します。「1,240件中50件を表示」と、続きを表示する方法を示します。無限スクロールでは、終端を見えるようにし、フッターにたどり着く方法を用意します。
- 段階的に表示する場合は、到着したものから描画します。最も遅いリクエストを待ってはいけません。
- ストリーミングリストでは、ユーザーが読んでいる内容を動かさずに末尾へ追加します。ビューポートより上に新しい項目がある場合は、ページをずらすのではなく「新着3件」ピルを表示します。
エラー
エラーでは、次の3つをこの順番で伝えます。
- 何が起きたかを、わかりやすい言葉で伝えます(「変更を保存できませんでした」)。
- ユーザーが対処するのに役立つ場合は、その理由を伝えます(「オフラインです」「その名前はすでに使われています」)。
- 何をすべきかを、行動として伝えます(「もう一度お試しください」「別の名前を選んでください」)。
表示位置は、原因のできるだけ近くにします。フィールドのエラーはフィールドの下に、保存エラーは保存ボタンの隣に、領域のエラーはその領域内に、ページのエラーはページ内に表示します。ユーザー自身で解決する必要がある問題を、トーストで表示してはいけません。
スタックトレースや、ステータスコードだけの表示、対処方法を伴わない「問題が発生しました」は、決して表示しません。更新に失敗しても画面上のデータは残し、空白にするのではなく古いデータとして示します。
ネットワークの一時的な切断には、1回だけ自動で静かに再試行します。その後はユーザーが判断します。
楽観的更新
切り替え、並べ替え、名前の変更、いいねなど、失敗率の低い操作では、次のようにします。
- 同じフレーム内でインターフェースを変更します。
- リクエストを送信します。
- 失敗した場合は元に戻し、失敗した箇所で説明します。
楽観的に追加した項目には安定した ID を割り当て、後から再取得したデータと統合するときに重複しないようにします。金銭、元に戻せない削除、またはユーザーが簡単に元に戻せたことを確認できない操作には、この方法を使いません。
古いデータとオフライン
- 古い可能性のあるデータは、非表示にせず「4分前に更新」のように表示します。
- オフライン時は、モーダルではなく、画面に常時表示される控えめなバーを使います。読み取りはキャッシュから続行でき、書き込みはキューに入れて、その旨を伝えます。
- 接続が戻ったら同期し、バーを消します。ページを再読み込みしてはいけません。
未保存の変更
- 状態を表示します。タブタイトルの横にドットを付け、操作の近くに「保存済み」/「保存中…」/「未保存」のラベルを表示します。
- 誤った保存による損失が小さい場合は自動保存し、そうでない場合は明示的な保存を使います。
- 失うものがある場合に限ってページ移動時に警告し、何が失われるかを伝えます。
- 入力内容を決して失わせません。下書きはローカルストレージから復元できるようにします。
成功
- 操作した場所で示します。ボタンには1.5秒間「保存済み」と表示し、行を更新して、件数を増やします。
- 効果が別の場所に現れる場合に限り、トーストを表示します(「読書リストに追加しました」)。
- 全画面での成功表示は、登録、支払い、オンボーディングの完了など、一度限りのイベントに使います。
- 「正常に保存されました」のような表現は使いません。何が変わったかを伝えます。
状態間の遷移
- スケルトンからコンテンツへ:動きを伴わず、200ms でクロスフェードします。
- コンテンツからエラーへ:揺らさず、その場で置き換えます。
- 空の状態から最初の項目へ:項目が表示され、空の状態のメッセージが消えます。両方を同時にアニメーションさせてはいけません。
- ユーザー自身の操作による状態変化は、サーバーによる状態変化より速くします。
チェックリスト
- データを取得するすべての領域に、スケルトン、空の状態、エラー、再取得の状態がある
- データが届いても、何も動かない
- 150ms 未満では読み込みインジケーターを表示しない。表示した場合は300ms 未満で消さない
- 再取得中も既存のデータを画面に残す
- 空の状態には操作を1つ用意する
- エラーには対処方法を示し、原因の隣に表示する
- 楽観的更新が元に戻るときは、その理由を説明する
- 古いデータは非表示にせず、その旨を示す
- 成功は操作した場所に表示する
カタログから
- Page Flows — 公開中のプロダクトにおける、オンボーディング、空の状態、エラーの画面遷移を記録しています。
- Nielsen Norman Group — 応答時間の制限と、その根拠となる調査を紹介しています。
- Mobbin — 「empty state」や「error」で検索すると、実際のアプリでの対応例を確認できます。
- Smashing Magazine — スケルトン画面と体感パフォーマンスに関する詳しい記事を掲載しています。
- その他の資料は stealth.pm/look をご覧ください。