この記事の要点(UIXHERO視点) UIXHEROでは、ドハティの閾値を「システムとユーザーが会話するように対話できる応答速度の限界点(0.4秒)」と定義する。 本記事では、物理的な速度の向上だけでなく、楽観的UIやスケルトン表示によって「待たされている」と感じさせない体感速度の向上策を整理する。
ドハティの閾値とは?
1982年、Walter J. DohertyとArvind J. Thadaniは、コンピューターの応答時間が 0.4秒(400ms) を下回ると、ユーザーの生産性が飛躍的に向上することを発見しました。 この閾値を超えると、ユーザーは注意散漫になり、システムに対する「対話感」が失われます。現代のUXにおいても、0.4秒ルールは「体感速度」の基準として重要です。
なぜ重要なのか
人間は、道具(システム)が自分の思考と同じ速度で反応するとき、その道具を身体の一部のように感じます(フロー状態)。 反応が遅いと、ユーザーは「待たされている」と意識してしまい、その瞬間に魔法が解け、フロー状態から脱落してしまいます。
現代のUXでの活用事例
実際には、すべての処理を0.4秒以内に完了させるのは技術的に不可能な場合もあります。そのための工夫が必要です。
1. 楽観的UI (Optimistic UI)
「いいね(Make)」ボタンを押した瞬間、サーバーからの完了レスポンスを待たずに、UI上では「いいね完了」を表示してしまう手法です。これにより、体感速度は0秒になります。
2. 即時の視覚フィードバック
重い処理を実行する場合でも、ボタンを押した瞬間(0.1秒以内)に「処理中」のローディング表示を出します。「処理開始を受け付けた」という反応だけでも0.4秒以内に返すことが重要です。
3. スケルトンスクリーン
コンテンツの読み込み中に、真っ白な画面を見せるのではなく、枠組み(スケルトン)を先に表示することで、体感的な待ち時間を減らします。
実装例: 応答速度の違いと体感
ボタンを押してからフィードバックが返ってくるまでの時間が、ユーザー体験にどう影響するかを比較するデモです。 0.4秒の壁を超えると、一瞬の「間」を感じるはずです。
Interactive Example (Live)
const ResponseComparison = () => { const [fastStatus, setFastStatus] = useState('idle'); const [slowStatus, setSlowStatus] = useState('idle'); // 0.4秒未満 (ドハティの閾値内) const handleFastClick = () => { setFastStatus('loading'); setTimeout(() => { setFastStatus('success'); setTimeout(() => setFastStatus('idle'), 1500); }, 300); // 300ms }; // 1.0秒 (閾値超え) const handleSlowClick = () => { setSlowStatus('loading'); setTimeout(() => { setSlowStatus('success'); setTimeout(() => setSlowStatus('idle'), 1500); }, 1000); // 1000ms }; return ( <div className="p-8 bg-muted/30 rounded-xl flex flex-col items-center gap-8"> {/* Fast Response Case */} <div className="w-full max-w-sm"> <div className="flex justify-between items-center mb-2"> <h4 className="font-bold text-foreground">Within Threshold (300ms)</h4> <span className="text-xs bg-green-100 dark:bg-green-950 text-green-700 dark:text-green-200 px-2 py-1 rounded">Good UX</span> </div> <button onClick={handleFastClick} disabled={fastStatus !== 'idle'} className={`w-full py-3 rounded-lg font-medium transition-all ${ fastStatus === 'idle' ? 'bg-primary hover:bg-primary/100 text-white shadow-md' : fastStatus === 'loading' ? 'bg-blue-300 dark:bg-blue-800 text-white cursor-wait' : 'bg-green-600 text-white' }`} > {fastStatus === 'idle' && 'Click Me (Fast)'} {fastStatus === 'loading' && 'Loading...'} {fastStatus === 'success' && 'Done!'} </button> <p className="text-xs text-muted-foreground mt-1"> 反応が即座に感じられ、自分の操作の一部のように思えます。 </p> </div> <div className="w-full border-t border-border"></div> {/* Slow Response Case */} <div className="w-full max-w-sm"> <div className="flex justify-between items-center mb-2"> <h4 className="font-bold text-foreground">Above Threshold (1000ms)</h4> <span className="text-xs bg-red-100 dark:bg-red-950 text-red-700 dark:text-red-200 px-2 py-1 rounded">Frustrating</span> </div> <button onClick={handleSlowClick} disabled={slowStatus !== 'idle'} className={`w-full py-3 rounded-lg font-medium transition-all ${ slowStatus === 'idle' ? 'bg-gray-600 hover:bg-muted/300 text-white shadow-md' : slowStatus === 'loading' ? 'bg-gray-300 text-white cursor-wait' : 'bg-green-600 text-white' }`} > {slowStatus === 'idle' && 'Click Me (Slow)'} {slowStatus === 'loading' && 'Loading...'} {slowStatus === 'success' && 'Done!'} </button> <p className="text-xs text-muted-foreground mt-1"> 一瞬の「間」があり、システムが止まったのか不安になります。 </p> </div> </div> ); }; render(<ResponseComparison />);
倫理的配慮 (Ethical Considerations)
- 人工的な遅延 : 処理が速すぎる場合(0.1秒未満)に、あえて少し遅延させる(アニメーションを入れる)ことがあります。速すぎる変化はユーザーが見逃してしまう可能性があるためです。
- 中毒性 : 即時のフィードバックは快感を生み、SNSの「いいね」のような中毒性のあるインターフェース(スロットマシン効果)に直結します。