はじめに
ユーザーにとって「待ち時間」はストレスの元です。
システムの処理上で複雑な処理や大きいサイズのデータを扱う際には必ず待ち時間が発生しています。
世に出ている多くのWebアプリケーションではローディングを実装してユーザーの意識の外で、いかにして「体感時間」を減らすかという工夫が凝らされています
この記事では、そんな体感時間を減らすためのローディング処理にはどんなものがあるのかをまとめてみました!
今回紹介するローディング処理
- スケルトンスクリーン
- ブラーアップ
- プログレスバー
- オプティミスティックUI
- ボタン内ローディング
- 無限スクロールの読み込みトリガー
- ステップウィザード
- バックグラウンド処理 & トースト通知
1. スケルトンスクリーン (Skeleton Screen)
コンテンツのレイアウト構造をロード前に事前に表示することで、読み込みによる画面のガタつきを防いで体感的な待ち時間を短縮します。
FacebookやLinkedInなど規模の大きなサービスで採用されている手法ですね。
ユーザー目線では「何かが読み込まれている」ということが視覚的にわかるので真っ白な画面でただ待たされるよりもストレスが少ないです。
仕組み
画像やテキストなどのコンテンツと同じサイズ・余白で要素を作って実際のコンテンツと同じ構造にすることで、読み込み完了時のガタつきを防ぐことができます。
2. ブラーアップ / LQIP
高画質画像の読み込み中に、低解像度のボケた画像を表示しておく手法です。Instagramなどの画像が主体なSNSでも採用されていて、見たことがある方も多いのではないでしょうか。
真っ白な状態からいきなり画像が現れるよりも、ぼんやりとした画像から徐々にクリアになっていく方が、視覚的に自然で心地よく感じます。
仕組み
onLoad イベントでフラグを切り替え、CSSの opacity と transition でフェードインさせるのが最もスムーズだと思います。blur-lg と scale-110 を組み合わせることで、ブラーの端が見えなくなってより自然な見た目になります。
ただし scale-110 で拡大する場合、親要素に overflow-hidden を設定しておかないと画像が枠からはみ出してレイアウトが崩れるので注意が必要です。
デモ
3. プログレスバー (Progress Bar)
ファイルアップロードなど、終了時間が予測できない処理でも「動いている」ことを可視化し、ユーザーの不安を解消するための手法です。
逆に、処理を実行したのに何も反応がなかったり情報がない状態だと「本当に動いているのか?」「フリーズしたのでは?」と不安になってしまいます。
「あとどれくらい待てばいいのか」が分かると、ユーザーは安心して待つことができますね。
仕組み
進捗率がリアルタイムに取れない場合でも、嘘の進捗(Fake Progress)を少しずつ進めることで「フリーズしていない」安心感を与えられます。プログレスバーの進め方によってはユーザーに心理的な不安やストレスを与える可能性があるので注意が必要です。
特にプログレスバーの99%で止まって待たされるのはストレスなので、最後の数%は慎重に扱いましょう。
4. オプティミスティックUI (Optimistic UI)
サーバーからのレスポンスを待たずに、画面上では「成功した」ものとして即座にUIを更新します。チャットアプリや「いいね」ボタンに必須の技術です。
TwitterやSlackでメッセージを送信した瞬間に画面に表示されるのを見たことがあると思います。
サーバーの応答を待っていたら、ワンテンポ遅れてストレスフルな体験になってしまいます。
仕組み
成功を前提にUIを更新しつつ、エラー時のロールバック処理(元の状態に戻す、または再試行ボタンを出す)を必ずセットで実装します。楽観的更新だけして、エラーハンドリングを忘れると大変なことになるので注意が必要です。
また、送信成功時にサーバーから返ってきた確定値(IDなど)で最終的にStateを上書きすることも大切です。クライアント側で仮のIDを振っていたとしても、サーバーが発行した正式なIDに置き換えるような処理ですね。React QueryやSWRを使っている場合は、この辺りの処理を自動でやってくれます。
5. ボタン内ローディング (Button Loading)
ボタンをクリックした直後にローディング状態に変化させ、連打(二重送信)を防止しつつ処理中であることを伝えます。
フォーム送信やデータ保存など画面操作時に少しサーバー側の処理で少しラグがある場合に必須な処理です。ボタンが押せる状態のままだとユーザーは不安になったり、誤操作で何度もクリックしてしまいます。
そうすると余分なリクエストまで送信されてしまってサーバー側の負荷やデータ整合性等に影響が出ますのでほぼ必須の実装といっても良いかもしれませんね。
仕組み
disabled 属性の付与を忘れないようにしましょう。ShadCN/uiのButtonコンポーネントとlucide-reactのLoader2アイコンを組み合わせると、簡単に実装できます。
またアイコンとテキストを両方変えることで、より明確にフィードバックできます。
アクセシビリティを考慮するなら、aria-busy="true" や aria-disabled="true" といったARIA属性を付けておくとスクリーンリーダー利用者にも「処理中である」ことが伝わります。
6. 無限スクロールの読み込みトリガー
「もっと見る」のようなボタンを押させるのではなく、スクロールに合わせて自然にコンテンツを追加読み込みします。
TwitterやInstagramのフィードを思い浮かべるとイメージしやすいと思います。
わざわざリロードボタンを押さなくても、スクロールするだけで次々とコンテンツが読み込まれていきます。
ユーザーの操作負担を減らしつつ、エンゲージメントを高める効果もあります。
仕組み
IntersectionObserver APIを使うのが現代的な実装です。
rootMargin を設定して、ユーザーが底に到達する少し前に読み込みを開始させると、よりスムーズなユーザー体験になります。
これはスクロールイベントを使う古い実装よりもパフォーマンスが良いのでおすすめです。
Reactで実装する場合、useEffect のクリーンアップ関数で observer.disconnect() を呼んでObserverを解除しないとメモリリークの原因になります。コンポーネントがアンマウントされても監視が残り続けてしまうので、忘れずにクリーンアップしましょう。
7. ステップウィザード (Step Wizard)
処理が複数段階にわたる場合に処理の全体像と現在地を可視化するための手法です。
ユーザー登録フローや複数ページにわたるフォームなど、「今どこにいて、あと何ステップ残っているのか」が分かると、ユーザーは安心して進めることができます。
仕組み
進捗バーのアニメーションに transition-all を使うことで、ステップ間の移動がスムーズになります。ステップ数は3〜5個が理想的でそれ以上になってしまうと、「長すぎる」と感じて離脱しやすくなるので注意しましょう。
8. バックグラウンド処理 & トースト通知
CSVエクスポートなどの重い処理はバックグラウンドに回し、ユーザーの操作をブロックしないのが鉄則です。
特に数秒〜数十秒かかる処理で、ユーザーをモーダルやローディング画面に閉じ込めてしまうのは最悪のUXですので処理は裏で進めておきつつも、完了したらトーストで通知する方がユーザー体験は良いと思います。
仕組み
ユーザーを待機画面(モーダルなど)に拘束しないことがUX向上の鍵です。ShadCN/uiではsonnerまたはtoastコンポーネントが使えます。完了時にはアクションボタン(ダウンロードボタンなど)を付けるとさらに便利になります。
まとめ
ユーザーの「待たされている感」を減らすには、オプティミスティックUIやブラーアップのような「体感速度を上げる」テクニックが効果的です。
私たちが普段使っているSNSやチャットアプリ、その他多くのウェブアプリではこうした手法によってUI/UXを向上させる工夫がされています。
実際の処理時間は変わらなくてもユーザーが感じる速度は大きく変わってきます。
ローディングUXはユーザー体験を左右する重要な要素ですので、状況に応じた最適なパターンを選んで実装してみてください。