mcpField
L
loading-states-and-perceived-performance

loading-states-and-perceived-performance

github.com/dembrandtデザイン・UI174887 回インストール1 週間前に更新
リポジトリ

loading-states-and-perceived-performance について

読み込み状態と体感速度を設計するスキルです。デザイナーや開発者向けに、表示パターンの選択、コンテンツの優先読み込み、短縮できない待ち時間への対応を解説します。

主な機能

  1. 01待ち時間に応じた表示の選択
  2. 02レイアウトに合うスケルトン画面
  3. 03コンテンツ優先と不要データの遅延
  4. 04予測可能な次の操作の先読み
  5. 05ロールバック可能な楽観的更新
  6. 06遅いリクエストと長時間ジョブの区別

活用シーン

  1. 01ボタン操作やデータ取得の表示設計
  2. 02ダッシュボードやページの段階的読み込み
  3. 03アップロードやエクスポート中の応答感の改善

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dembrandt/dembrandt-skills --skill loading-states-and-perceived-performance

インストール後、Claude Code で/loading-states-and-perceived-performanceを入力して読み込まれたか確認します。

詳細

ローディング状態と体感速度

ユーザーは、何を待っているのか、どれくらい進んでいるのかが分かれば、待ち時間をそれほど気にしません。体感速度を高めるとは、実際よりもシステムが速く感じられるように設計することです。


適切なローディング状態を選ぶ

待ち時間最適なパターン用途
短い(< 1s)インラインスピナー/ローダーボタン操作、小規模な更新、素早いデータ取得
中程度(1s – 3s)スケルトンスクリーンカード、リスト、ダッシュボード、プロフィールページ
長い(> 3s)進捗確定型プログレスバーファイルのアップロード、複雑なエクスポート、負荷の高い処理
フルページ段階的な表示/セクションのアニメーションアプリの初回読み込み、ヒーローセクション、没入感のあるトランジション

シンプルなケース:スピナーとローダー

レイアウトが大きく変わらない、小規模で範囲の限られた操作にはスピナーを使用します。

  • ボタンのスピナー: ボタンのテキストと置き換えるか、テキストの横に表示します。二重送信を防ぐため、ボタンを disabled 状態にしてください。
  • マイクロローダー: インライン更新(例:単一フィールドの保存)には、16〜24pxの小さな円を使用します。
  • アニメーションのヒント: 一定速度で回転するアニメーションよりも、「スプリングのような」回転(加速と減速を伴うイージング)のほうが、洗練された印象になります。
@keyframes spin {
  0%   { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
.spinner {
  animation: spin 800ms cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

スケルトンスクリーン(グリマー/シマー)

スケルトンスクリーンは、最終的なコンテンツのレイアウトを模した視覚的なプレースホルダーです。これにより「レイアウトシフト」(CLS)を抑え、コンテンツが表示される場所をユーザーに正確に伝えます。

シマー効果

スケルトン要素の上を移動する、控えめなグラデーションです。

.skeleton {
  background: var(--color-grey-100);
  background-image: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.5) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}

@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
スケルトンのルール
  • 形状を合わせる: 最終的なコンテンツが丸いアバターなら、丸いスケルトンを使用します。2行の見出しなら、幅の異なるバーを2本使用します。
  • 控えめにする: スケルトンには最も目立たないグレー(--color-grey-100 または grey-50)を使用します。視線を引きつけないようにしてください。
  • 自然に切り替える: データが届いたら、瞬時に切り替えるのではなく、スケルトンの上に実際のコンテンツをフェードインさせます(150〜200ms)。

セクション全体にアニメーションを適用する

大きなページ遷移や初回読み込みには、連動したアニメーション戦略を使用します。

段階的な表示(カスケード)

ページ全体を一度に表示するのではなく、セクションを順番にアニメーション表示します。これにより、最も重要なコンテンツ(ヒーロー)から二次的な領域へと、ユーザーの視線を誘導できます。

.section {
  opacity: 0;
  transform: translateY(10px);
  animation: slide-up 400ms ease-out forwards;
}
/* Stagger by index */
.section:nth-child(1) { animation-delay: 100ms; }
.section:nth-child(2) { animation-delay: 200ms; }
.section:nth-child(3) { animation-delay: 300ms; }

@keyframes slide-up {
  to { opacity: 1; transform: translateY(0); }
}
ヒーローセクションの「ブルーム」

ヒーローセクションには、より複雑なアニメーションを使用できます。

  1. 背景画像をゆっくりフェードインさせます。
  2. 見出しをわずかに行き過ぎる動き(スプリング)でスライドインさせます。
  3. CTAボタンを最後に、くっきりとフェードインさせるか、控えめな色の変化とともに表示します。

優先順位に沿って読み込み、次の内容を先読みする

何も表示する前にすべての読み込みを待つ必要はありません。ユーザーにとっての価値に沿った順序で読み込み、ユーザーが求めているものを最初に表示し、その周囲に残りの内容を埋めていきます。これは体感速度だけでなく、コードの効率性も高めます。最初に取得して描画するデータが少なくなるためです。

  • まず、最も価値の高いコンテンツから — 重要な数値、主要なレコード、スクロールせずに見える範囲の回答を、準備でき次第すぐに描画します。
  • 次に、その次の優先度の内容を順に — 二次パネル、関連リスト、スクロールして表示するセクションを後から読み込みます(スケルトンで表示領域を確保し、レイアウトシフトを防ぎます。上記のスケルトンセクションを参照してください)。
  • 現在のビューに必要なデータだけを取得します。 タブ、ドロワー、画面外のセクションのデータは、ページ全体のデータを一度に読み込まず、開かれるまで後回しにします。

次に進むと予測できるステップを先読みします — 次のページ、ホバーした行の詳細、ウィザードの次のステップなどをバックグラウンドで読み込み、すぐに表示できるようにします。すべてを推測で読み込むのではなく、次の操作が明らかな場合に限って行います。

上級編:楽観的 UI

最も速い UI は、サーバーをまったく待たないものです。

  • パターン: サーバー呼び出しが成功すると想定して、すぐに UI を更新します。失敗した場合は元に戻し、エラーを表示します。
  • 用途: 投稿への「いいね」、スイッチの切り替え、フォルダーの名前変更、メッセージの削除。
  • メリット: ユーザーはすぐに結果を得られ、アプリが「電光石火」のように感じられます。

待ち時間に楽しさを加える

読み込みは、無味乾燥な体験である必要はありません。2 秒を超える待ち時間では、ユーザーの関心を保つために、ブランドらしさや「楽しさ」を加えることを検討してください。

ブランドに合ったマイクロコピー

一般的な「読み込み中…」というテキストを、ブランドのトーンを反映した文言に置き換えます。

  • 技術的: 「データをコンパイル中…」、「クラウドと同期中…」
  • 遊び心のある表現: 「ピクセルを集めています…」、「ダッシュボードを準備中…」、「もうすぐです!」
  • プロフェッショナル: 「レポートを準備中…」、「詳細を確認中…」
ブランドを反映したアニメーション(Lottie/SVG)

(アプリの初回起動や複雑なデータ処理など)重要な読み込み時には、標準のスピナーを、ブランドに特化した小さなアニメーションに置き換えます。

  • デザインツールなら、鉛筆が線を描く様子を表示できます。
  • フィットネスアプリなら、鼓動するハートや走る人のアイコンを表示できます。
  • 金融ツールなら、積み上がるコインや、上昇するグラフの線を表示できます。
プログレッシブなストーリーテリング

待ち時間が常に長い(3 秒以上)場合は、読み込み領域を使って短いストーリーを伝えたり、役立つ情報を提供したりします。

  • ヒントとコツ: 「Ctrl+K で検索できることをご存じですか?」
  • 処理の透明性: システムが行っている処理を表示します:「データベースを確認中…」→「結果を最適化中…」→「表示を仕上げています…」
視覚的なトランジション(表示時)

読み込み状態からコンテンツに切り替える際は、150ms の明瞭なフェードインを使い、表示を報酬のように感じさせます。入ってくるコンテンツの拡大縮小は、レイアウトが不安定になる可能性があるため避けてください。

カーソルは読み込み状態を示すものではありません

カーソルは操作可能性を示します。通常のコンテンツには矢印、操作できる要素には pointer を使います。進行状況を示すものではありません。cursor: wait や cursor: progress では、ユーザーが見ていない場所に状態が表示され、何を読み込んでいるのか、どのくらい進んでいるのかも伝わらず、ポインターを動かした瞬間に消えてしまいます。実際に待機している要素や領域に進行状況を表示してください。コントロールについては [[button-states]] で、領域については上記のスケルトンおよび進行状況のパターンで説明しています。

ローディング状態ではできないこと

ローディング状態によって、ユーザーに待ってもらうことはできます。しかし、時間を短縮することはできず、失敗するリクエストを救うこともできません。以下のしきい値は、新たな発見ではなく、長年にわたって確立されてきた応答時間の限界です。ここから導かれることは、通常見落とされがちな点です。

  • 約10秒まで: スピナーやスケルトンで待ち時間に対応できます。
  • それを超える場合: インターフェースには、実際の進捗状況とキャンセルする手段が必要です。不確定なアニメーションは情報ではなくなり、未知の状態を覆い隠す装飾になります。
  • 約30秒を過ぎると: どのようなアニメーションが表示されていても、ユーザーはアプリケーションが応答しなくなったと判断し、再読み込みしたり離脱したりし始めます。

リクエストが常にこうしたしきい値を超えるなら、修正すべきなのはリクエストです。 バックエンドのタイムアウトに向かっているときに、表示を充実させても、ユーザーがいずれ受け取るエラーを遅らせるだけです。その間、プロダクトが壊れていることをチームから隠してしまいます。スピナーによって失敗が後回しになるため、誰も原因を修正せず、ユーザーは結局タスクを放棄します。

待ち時間を本当に短縮できない場合、修正すべきなのはリクエストでもありません。 大規模なエクスポート、モデルの呼び出し、動画のトランスコードなど、かかる時間を短縮できない処理もあります。インジケーターを表示しても、処理時間は短くなりません。そうした場合は、処理を画面の外に移すのが解決策です。ジョブを受け付け、実行中であることをユーザーに伝え、ほかのことに取り組めるようにし、完了したら通知します。結果は、ユーザーが見つけられる場所に保存しておきます。進捗バーの前に2分間ユーザーを引き留めるのは一つの選択ですが、ユーザーがそうしたいと思うことはほとんどありません。避けるべきなのは、短縮できない待ち時間をパフォーマンスのバグとして扱い、最適化可能な待ち時間を仕方のないこととして扱うことです。この2つには正反対の対応が必要なので、待ち時間を設計する前に、どちらに当たるのか判断してください。


レビューチェックリスト

  • 想定される待ち時間に適したローディング状態(スピナーかスケルトンか)になっていますか?
  • スケルトン画面は、読み込まれるコンテンツの実際のレイアウトと一致していますか?
  • スケルトンには、「読み込み中」であることを示す控えめなシマーアニメーションがありますか?
  • 二重操作を防ぐため、読み込み中はボタンが無効になっていますか?
  • コンテンツは突然表示されるのではなく、スケルトン上にフェードイン(150~200ms)しますか?
  • ページ全体を読み込む場合、視線を誘導するために段階的な表示を使っていますか?
  • すべてのローディングアニメーションでprefers-reduced-motionを尊重していますか?
  • 「楽観的UI」の場面では、操作に失敗した場合に明確なロールバック手順がありますか?
  • コンテンツは優先順位の高いものから読み込み(残りは順次表示)、最初にすべてを読み込むのではなく、現在のビューに必要なものだけを取得していますか?
  • 次のステップが予測可能な場合、すべてを投機的に読み込むことなく、事前読み込みして瞬時に表示できるようにしていますか?

よくあるアンチパターン

アンチパターン問題修正方法
アプリ全体をブロックするグローバルスピナー強い不満につながり、ユーザーがほかの領域を閲覧できません状況に応じたローダーやスケルトンを使います
最終的なレイアウトと一致しないスケルトンデータの到着時にレイアウトが大きくずれます(CLS)形状とサイズを正確に一致させます
1ページにスピナーが多すぎる視覚的なノイズになり、アプリ全体が壊れているように感じられますローディング状態を1つのコンテナスケルトンにまとめます
光速より速いスケルトンシマーアニメーションが速すぎる、またはコントラストが強すぎますシマーはゆっくり(1.5秒以上)、ごく控えめにします

コメント