Perceived Performance

체감 성능

How fast something feels, not how fast it actually is. The same total wait can feel very different depending on how it's shown.

Also known as: Perceived speed
···
html
<div class="stage">
  <div class="pane"><div class="tag">✗</div>
    <div class="spin" id="sp"></div>
    <div class="loaded" id="l1"><div class="av"></div><div class="ln"></div><div class="ln short"></div></div>
  </div>
  <div class="pane"><div class="tag">✓</div>
    <div class="sk" id="sk"><div class="sk-av"></div><div class="sk-ln"></div><div class="sk-ln short"></div></div>
  </div>
</div>
css
.stage{width:94%;height:88%;display:flex;gap:6%}
.pane{position:relative;flex:1;border-radius:14px;border:1px solid var(--line);background:var(--surface);display:grid;place-items:center;overflow:hidden}
.tag{position:absolute;top:8px;left:10px;font:700 10.5px/1 monospace;color:var(--muted)}
.spin{width:22px;height:22px;border-radius:50%;border:3px solid var(--line);border-top-color:var(--accent);animation:spin .8s linear infinite}
.spin.hide{display:none}
.loaded{display:none;width:70%;gap:8px}
.loaded.show{display:grid}
@keyframes spin{to{transform:rotate(360deg)}}
.av{width:34px;height:34px;border-radius:50%;background:var(--accent)}
.ln{height:9px;border-radius:4px;background:var(--fg);opacity:.7}
.short{width:60%}
.sk{width:70%;display:grid;gap:8px;grid-template-columns:auto 1fr;align-items:center}
.sk-av{width:34px;height:34px;border-radius:50%;grid-row:span 2;background:linear-gradient(90deg,var(--line) 25%,var(--surface) 50%,var(--line) 75%);background-size:200% 100%;animation:shimmer 1.2s linear infinite}
.sk-ln{height:9px;border-radius:4px;background:linear-gradient(90deg,var(--line) 25%,var(--surface) 50%,var(--line) 75%);background-size:200% 100%;animation:shimmer 1.2s linear infinite}
.sk-ln.short{width:60%}
@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
js
const sp = document.getElementById('sp');
const l1 = document.getElementById('l1');
function run() {
  sp.classList.remove('hide'); l1.classList.remove('show');
  setTimeout(() => { sp.classList.add('hide'); l1.classList.add('show'); }, 2400);
}
run();
setInterval(run, 3400);

Amazon's own 2006 research found that every 100ms of added page-load time cost roughly 1% in sales — but interestingly, *perceived* speed doesn't track actual speed one-to-one. A stretch of time with zero visible activity feels unusually long; the same duration with something visibly moving feels shorter.

That's why a skeleton screen (see: skeleton-screen) or progressive content reveal reduces drop-off without shrinking real load time at all. Where the Doherty Threshold is about immediate reaction, this is about how the *wait after that* is experienced.

Over the same 2.4 seconds, left shows only a spinner on a blank screen before content pops in all at once; right shows a skeleton instantly and fills content in progressively.

When to use

For any load over 400ms, prefer a skeleton or progressive reveal over a lone spinner. You can cut drop-off even without cutting real load time.