스켈레톤

Skeleton

실제 콘텐츠가 도착하기 전, 그 레이아웃 모양을 흉내 낸 회색 블록으로 로딩 중임을 보여주는 상태.

다른 이름: Skeleton screenContent placeholderGhost loading
···
html
<div class="skw" aria-hidden="true">
  <div class="sk-row">
    <div class="sk sk-avatar"></div>
    <div class="sk-lines"><div class="sk sk-line" style="width:70%"></div><div class="sk sk-line" style="width:45%"></div></div>
  </div>
  <div class="sk sk-block"></div>
</div>
css
.skw{width:min(230px,90%);display:grid;gap:12px}
.sk-row{display:flex;gap:10px;align-items:center}
.sk-lines{flex:1;display:grid;gap:7px}
.sk{border-radius:6px;background:linear-gradient(100deg,var(--line) 30%,color-mix(in srgb, var(--line) 40%, var(--surface)) 50%,var(--line) 70%);
  background-size:200% 100%;animation:shimmer 1.4s ease-in-out infinite}
.sk-avatar{width:40px;height:40px;border-radius:50%;flex-shrink:0}
.sk-line{height:9px}
.sk-block{height:44px;border-radius:9px}
@keyframes shimmer{0%{background-position:120% 0}100%{background-position:-20% 0}}

실제 콘텐츠와 같은 크기·배치의 회색 블록을 미리 그려두고, 데이터가 도착하면 자리를 바꾸지 않고 그대로 내용만 채워 넣습니다. 그래서 레이아웃이 갑자기 밀리는 현상(레이아웃 시프트)이 줄어들고, 빈 화면보다 "곧 뭔가 나올 것"이라는 예측이 가능해 체감 속도가 빨라집니다.

스피너와의 차이는 위에서 다룬 대로입니다 — 스피너는 "로딩 중" 사실만 알리고 스켈레톤은 콘텐츠의 미래 모습을 미리 보여줍니다. 은은하게 왼쪽에서 오른쪽으로 훑고 지나가는 반짝임(shimmer)은 CSS 그라데이션을 background-position으로 움직여 만듭니다.

접근성 관점에서는 스켈레톤 블록 자체를 스크린리더가 읽을 필요는 없으니 aria-hidden="true"를 주고, 로딩 시작/완료는 별도의 aria-live 영역으로 알리는 게 좋습니다.