Skeleton Screen

스켈레톤 스크린

Grey placeholder blocks shaped like the content that's about to load, shown before the real thing arrives — it shortens perceived wait time versus a blank screen.

Also known as: Skeleton loaderGhost content
···
html
<div class="card">
  <div class="row">
    <div class="av sk" id="av"></div>
    <div class="col">
      <div class="ln title sk" id="t1"></div>
      <div class="ln sub sk" id="t2"></div>
    </div>
  </div>
  <div class="ln body sk" id="b1"></div>
  <div class="ln body short sk" id="b2"></div>
</div>
css
.card{width:78%;max-width:280px;padding:16px;border-radius:14px;border:1px solid var(--line);background:var(--surface);display:grid;gap:10px}
.row{display:flex;gap:10px;align-items:center}
.col{flex:1;display:grid;gap:6px}
.av{width:38px;height:38px;border-radius:50%}
.ln{height:9px;border-radius:4px}
.title{width:60%}
.sub{width:40%}
.body{width:100%}
.short{width:70%}
.sk{background:linear-gradient(90deg,var(--line) 25%,var(--surface) 50%,var(--line) 75%);background-size:200% 100%;animation:shimmer 1.2s linear infinite}
@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
.done{animation:none !important;background:none !important}
.av.done{background:var(--accent) !important}
.title.done{background:var(--fg) !important;opacity:.85}
.sub.done,.body.done{background:var(--muted) !important;opacity:.6}
js
const ids = ['av','t1','t2','b1','b2'];
const els = ids.map(id => document.getElementById(id));
let done = false;
setInterval(() => {
  done = !done;
  els.forEach(e => e.classList.toggle('done', done));
}, 1800);

Designer Luke Wroblewski and others named and popularised the pattern in the early 2010s, and it spread widely once Facebook rolled it into its apps around 2013–2014. A spinner only says "something is loading"; a skeleton sets a structural expectation — "content shaped like this is coming."

So even with identical real load time, a skeleton feels like a shorter wait than a spinner (see: perceived-performance). But if the skeleton's shape doesn't match the real content closely enough — say, drawing an image block for a card that turns out to have no image — the layout jumps jarringly once it resolves.

The card below starts as shimmering grey blocks, periodically resolves into real content (a coloured avatar, dark text), then resets back to skeleton.

When to use

Use it for predictably structured content — cards, lists, profiles. Match the skeleton's size and count to the final layout closely to avoid a jarring shift once it resolves.