Skeleton
Import
<link rel="stylesheet" href="/guide/css/base/index.css" /> <link rel="stylesheet" href="/guide/css/components/skeleton.css" />
Live
Primitives
Title (100%)
Text (80%)
Avatar (60×60px)
Image (100%×180px)
Patterns
Card
Profile
Paragraph
Specs
| 요소 | Height | Width | Border Radius | 색상 |
|---|---|---|---|---|
| Base | — | — | --radius-md (8px) | --gray-200 (shimmer: --gray-100) |
| Title | 27px | modifier 참고 | --radius-md (8px) | — |
| Text | 24px | modifier 참고 | --radius-md (8px) | — |
| Avatar | 60px | 60px | 50% (원형) | — |
| Image | 180px | 100% | --radius-md (8px) | — |
| Animation | skeleton-shimmer 1.5s ease-in-out infinite — 좌우 반복 shimmer | |||
Code
Base — 단일 라인
<!-- Title 라인 (100% 너비) --> <div class="skeleton skeleton--title skeleton--w-full"></div> <!-- Title 라인 (80% 너비) --> <div class="skeleton skeleton--title skeleton--w-80"></div> <!-- Text 라인 (60% 너비) --> <div class="skeleton skeleton--text skeleton--w-60"></div> <!-- Text 라인 (40% 너비) --> <div class="skeleton skeleton--text skeleton--w-40"></div> <!-- Avatar (60×60px 원형) --> <div class="skeleton skeleton--avatar"></div> <!-- Image 영역 (100%×180px) --> <div class="skeleton skeleton--image"></div>
Card Pattern
<div class="skeleton-card">
<div class="skeleton skeleton--image"></div>
<div class="skeleton-card__body">
<span class="skeleton skeleton--title skeleton--w-80"></span>
<span class="skeleton skeleton--text skeleton--w-60"></span>
<span class="skeleton skeleton--text skeleton--w-40"></span>
</div>
</div>
Profile Pattern
<div class="skeleton-profile">
<div class="skeleton skeleton--avatar"></div>
<div class="skeleton-profile__body">
<span class="skeleton skeleton--title skeleton--w-full"></span>
<span class="skeleton skeleton--text skeleton--w-60"></span>
</div>
</div>
Paragraph Pattern
<div class="skeleton-paragraph"> <span class="skeleton skeleton--title skeleton--w-full"></span> <span class="skeleton skeleton--text skeleton--w-80"></span> <span class="skeleton skeleton--text skeleton--w-60"></span> </div>
JavaScript — 로딩 후 콘텐츠 전환
const skeleton = document.getElementById('sk-skeleton');
const content = document.getElementById('sk-content');
const btn = document.getElementById('sk-btn');
let loaded = false;
btn.addEventListener('click', () => {
if (loaded) {
// 초기화: 스켈레톤으로 복귀
content.style.opacity = '0';
content.style.pointerEvents = 'none';
content.setAttribute('aria-hidden', 'true');
skeleton.style.opacity = '1';
btn.textContent = '로드 시작';
loaded = false;
return;
}
// 로딩 시작 (실제 프로젝트에서는 fetch() 등 비동기 작업)
btn.textContent = '로딩 중...';
btn.disabled = true;
setTimeout(() => {
skeleton.style.opacity = '0';
content.style.opacity = '1';
content.style.pointerEvents = '';
content.setAttribute('aria-hidden', 'false');
btn.textContent = '다시 보기';
btn.disabled = false;
loaded = true;
}, 1500);
});
Classes
| 클래스 | 태그 | 설명 |
|---|---|---|
.skeleton |
루트 | 기본 스켈레톤 블록 — shimmer 애니메이션 적용 |
.skeleton--title |
수정자 | 타이틀 높이 27px |
.skeleton--text |
수정자 | 본문 텍스트 높이 24px |
.skeleton--avatar |
수정자 | 원형 아바타 60×60px |
.skeleton--image |
수정자 | 이미지 영역 100%×180px |
.skeleton--w-full |
수정자 | 너비 100% |
.skeleton--w-80 |
수정자 | 너비 80% |
.skeleton--w-60 |
수정자 | 너비 60% |
.skeleton--w-40 |
수정자 | 너비 40% |
.skeleton-card |
루트 | 카드 패턴 래퍼 — 이미지 + 텍스트 세로 배치 |
.skeleton-card__body |
요소 | 카드 텍스트 영역 (흰 배경, gap 8px) |
.skeleton-profile |
루트 | 프로필 패턴 래퍼 — 아바타 + 텍스트 가로 배치 |
.skeleton-profile__body |
요소 | 프로필 텍스트 영역 |
.skeleton-paragraph |
루트 | 단락 패턴 래퍼 — 타이틀 + 텍스트 세로 배치 |