체감 속도는 실제 로드 시간이 아니라 ‘기다리는 동안 무엇을 보여주느냐’에서 갈립니다. 스켈레톤(레이아웃 시프트 방지)·블러업 이미지(빈 공백 제거)·부드러운 전환(도착의 자연스러움)을 함께 쓰면, 같은 시간이라도 “멈췄다”가 아니라 “곧 온다”로 느껴집니다.
요약
- 빈 화면은 ‘멈춤’으로, 윤곽이 보이는 화면은 ‘곧 옴’으로 인지된다 — 실제 시간은 같다.
- 스켈레톤은 들어올 자리를 미리 잡아 레이아웃 시프트(CLS)를 막는다.
- 블러업 이미지는 같은 자리·같은 크기에 미리보기를 깔아 이미지 영역의 빈 공백과 점프를 없앤다.
- 전환은 transform·opacity로만 — 60fps로 끊김 없이, prefers-reduced-motion은 존중한다.
사용자가 페이지를 열고 처음 마주하는 1~2초. 그 짧은 시간에 “이 사이트 괜찮네”와 “느리네, 닫을까”가 갈립니다. 재밌는 건, 그 판단이 실제 로드 시간보다 무엇을 보여주는가에 더 좌우된다는 점입니다. 그래서 우리는 기다림 자체를 디자인 대상으로 봅니다.
빈 화면은 왜 그렇게 길게 느껴질까요?
아무것도 없는 화면을 보면 사람의 뇌는 ‘진행 중’인지 ‘멈춤’인지 구분하지 못합니다. 그래서 불안해지고, 같은 2초도 길게 느껴집니다. 반대로 콘텐츠가 들어올 자리의 윤곽이 보이면 ‘저기에 곧 채워지겠구나’라고 인지해 같은 시간이 짧게 느껴집니다. 스켈레톤은 바로 이 인지를 노립니다.
기다림도 디자인합니다
'다시 로딩'을 누르면 스켈레톤이 콘텐츠로 채워집니다. 빈 화면보다 훨씬 덜 답답하죠.
숲세권 프리미엄 단지 — 콘텐츠가 도착했습니다.
이미지는 어떻게 ‘덜컹’ 없이 들어오나요?
텍스트보다 무거운 게 이미지입니다. 그냥 두면 이미지가 도착하는 순간 텅 빈 공백이 갑자기 채워지면서 아래 내용이 밀려 내려가죠. 블러업은 저용량 흐릿한 미리보기를 원본과 같은 자리·같은 크기에 먼저 깔아둡니다. 자리가 확정돼 있으니 원본이 와도 흔들림이 없고, 흐릿함 → 또렷함으로 자연스럽게 전환됩니다.
흐릿하게 먼저, 또렷하게 나중에
'다시 불러오기'로 저용량 미리보기→원본. avif·webp·반응형으로 더 가볍게.
그러면 CLS는 왜 그렇게 중요한가요?
CLS(누적 레이아웃 시프트)는 화면이 도중에 얼마나 ‘덜컹’하는지를 재는 지표입니다. 버튼을 누르려는 순간 광고나 이미지가 끼어들어 자리가 밀리면, 엉뚱한 곳을 누르고 짜증이 납니다. 스켈레톤과 블러업은 둘 다 ‘들어올 자리를 미리 확정한다’는 같은 원리로 CLS를 0에 가깝게 잡습니다. 보기에 부드러운 것과 측정값이 좋은 것이 여기서 일치합니다.
전환(모션)은 거기서 무슨 일을 하나요?
스켈레톤이 콘텐츠로 바뀌는 그 순간을 ‘딱’ 끊어버리면 오히려 거칠게 느껴집니다. 그래서 도착하는 순간을 opacity와 작은 transform으로 짧게 이어줍니다(보통 150~250ms). 이게 “화면이 살아 있다”는 인상을 만듭니다. 핵심은 width·top·box-shadow 같은 레이아웃·페인트 속성을 매 프레임 건드리지 않는 것 — 그건 끊김을 만듭니다.
모션이 누군가에겐 멀미가 되지 않나요?
됩니다. 그래서 prefers-reduced-motion을 켠 사용자에게는 스켈레톤의 반짝임과 전환을 끕니다. 동시에 로딩 영역에는 ‘불러오는 중’이라는 상태를 스크린리더가 읽을 수 있게 둡니다. 부드러움은 멋이 아니라 배려고, 배려는 꺼야 할 때 꺼지는 것까지 포함합니다.
그래서 셋을 ‘같이’ 쓰면 무엇이 달라지나요?
역할이 다르기 때문입니다. 스켈레톤은 텍스트·카드 영역의 윤곽을, 블러업은 이미지 영역의 공백을, 전환은 둘이 채워지는 ‘순간’을 맡습니다. 하나만 빠져도 어딘가에서 화면이 덜컹하거나 텅 비어 보입니다. 위 두 데모를 번갈아 눌러보면, 빈 화면 없이 “곧 온다”가 계속 이어지는 느낌을 직접 확인할 수 있습니다.
이 로딩 경험, 누가 어느 1~2초를 책임지나요?
기다림 1~2초는 셋이 구간을 나눠 맡습니다. 누가 어떤 빈틈을 메우고, 그게 측정값(CLS)으로 어떻게 잡히는지 한 표로 정리했습니다.
| 담당 | 메우는 빈틈 | 측정·체감 결과 |
|---|---|---|
| 스켈레톤 | 텍스트·카드 영역의 윤곽 | 자리 미리 확정 → CLS 억제 |
| 블러업 이미지 | 이미지 영역의 빈 공백 | 같은 크기 미리보기 → 점프 제거 |
| 모션·전환 | 스켈레톤→콘텐츠 '도착 순간' | 150~250ms로 부드럽게 이음 |
셋은 같은 원리('들어올 자리를 미리 확정')를 공유합니다. 그래서 하나만 빠져도 어딘가에서 화면이 덜컹하거나 텅 비어 보입니다.
그리고 이 체감 보정은 무거운 스피너 라이브러리가 아니라 표준 기술로만 돕니다. 두 데모를 구동하는 재료를 그대로 적어 둡니다.
여기서 말하는 개선은 '체감 속도'일 뿐, 실제 로드 시간은 이미지·코드 최적화가 따로 줄입니다. 다만 그 위에 이 표준 기술들을 얹으면, 같은 시간도 '곧 온다'로 느껴집니다.
이 작품에 들어간 기술
블러업·AVIF·반응형 이미지
빈 공백을 미리보기로 채우고 용량을 절반 이하로.
체감 속도와 Core Web Vitals
CLS·LCP를 잡는 실제 성능 작업.
부드러운 전환과 모션 설계
transform·opacity로 60fps, reduced-motion 존중.
| 항목 | 빈 화면 | 스켈레톤+블러업 |
|---|---|---|
| 체감 속도 | ‘멈춤’으로 인지 → 길게 느껴짐 | ‘곧 옴’으로 인지 → 짧게 느껴짐 |
| CLS(레이아웃 시프트) | 이미지 도착 시 콘텐츠 밀림 | 자리 미리 확정 → 0에 가깝게 |
| 이탈 | 닫을까 망설임 | 진행 중임을 신뢰하고 대기 |
스켈레톤을 쓰면 사이트가 실제로 빨라지나요?
스피너와 스켈레톤 중 무엇을 써야 하나요?
블러업 이미지는 왜 CLS에 좋은가요?
로딩 애니메이션이 접근성을 해치지 않나요?
이 세 가지를 꼭 같이 써야 하나요?
로딩 상태, 이렇게 만듭니다
스켈레톤·스피너를 언제 어떻게.
성능 담당자의 라이브 노트
체감과 측정값을 같이 끌어올리는 법.
INP — 누른 뒤 반응까지
상호작용 지연을 줄이는 실무.
이 글의 스켈레톤·블러업 데모는 이 페이지에서 실제로 동작하는 코드입니다(외부 라이브러리 0, 공유 스크립트로 구동). 여기서 말하는 개선은 ‘체감 속도’이며 실제 로드 시간과는 별개입니다 — 빠르게 만드는 건 이미지·코드 최적화 같은 성능 작업입니다. 날조된 사례·수치는 사용하지 않았습니다.