Skeleton Screen
Three 16 px lines (60/100/80%) driven by a dark shimmer in 1.5 s — minimal text skeleton, synchronous, zero JavaScript.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Loaders has 29 effects, including 4 free. Explore the category →
3 usage examples



How it works
The skeleton relies on two classes. .loader-skeleton is a flex column 200 px wide with gap: 12px; it holds three .skeleton-line elements, each 16 px tall with a 4 px border radius. Widths are set directly in CSS: the first line is 60% (120 px), the second 100% (200 px), the third 80% (160 px) — a short-long-medium profile that mimics the natural variation of real text. The measured total height of the block is 72 px (3 × 16 px + 2 × 12 px gap).
The single @keyframes shimmer moves background-position from 200% 0 to -200% 0, sweeping the gradient peak from right to left across 400% of the width. The gradient — linear-gradient(90deg, #1a1a24 25%, #2a2a34 50%, #1a1a24 75%) with background-size: 200% 100% — uses two dark tones: the base at rgb(26, 26, 36) and the peak at rgb(42, 42, 52), a difference of 16 per RGB channel. Duration is 1.5 s, ease curve, no delay on any of the three lines: all three shimmer in phase. Measured in Chromium, the position moves from ~80% to ~-134% in 500 ms, giving ~270% per second.
Two limitations to know before integrating. First, the code contains no @media (prefers-reduced-motion: reduce) rule: measured in Playwright with the preference emulated, the animation runs at the same speed — stop it manually (see Accessibility). Second, the sold HTML wraps the skeleton in a .demo-preview — the site's demo container with background: #0a0a0f and min-height: 300px — which is not needed for the effect itself: the useful structure is only the .loader-skeleton and its three children (see HTML Structure).
Accessibility
- prefers-reduced-motion not handled: no
@media (prefers-reduced-motion: reduce)rule in the sold CSS — measured, the animation runs at 1.5 s regardless of the user's preference. Add@media (prefers-reduced-motion: reduce) { .skeleton-line { animation: none } }to freeze the shimmer for affected users. - Semantic role missing: add
role="status"andaria-label="Loading"to.loader-skeleton(or to the parent element taking over), so screen readers can announce the loading state without reading through the three emptydivs. - Alternative text: the three
.skeleton-lineelements are empty graphical elements. Addaria-hidden="true"to each; the text announced in the accessibility tree should come from the parentrole="status", not from the children. - DOM removal:
.loader-skeletonmust be removed or hidden (display: none) as soon as real content is inserted, otherwise assistive technologies keep announcing a loading state for content that is already available.
Browser compatibility
Pure CSS — @keyframes, linear-gradient, background-size, animation: properties available in all current browsers without vendor prefixes since 2013. Zero dependencies.
Without CSS animations (very old browsers), the three lines appear as uniform dark gray blocks with no movement — the skeleton layout stays intact, only the shimmer disappears.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="loader-skeleton">
<div class="skeleton-line"></div>
<div class="skeleton-line"></div>
<div class="skeleton-line"></div>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Block width (CSS — .loader-skeleton { width }) |
200px | Total skeleton width; the line percentages are relative to it. 100% to fill the parent container; a fixed value to lock the layout. |
Spacing between lines (CSS — .loader-skeleton { gap }) |
12px | Vertical distance between each line. 8px for a dense list; 20px to mimic a more open line height. |
Line height (CSS — .skeleton-line { height }) |
16px | Thickness of each bar. Match the font size of the content being replaced: 14px for body text, 24px for a heading. |
Corner radius (CSS — .skeleton-line { border-radius }) |
4px | 0 for rectangular bars (tabular style); 8px for a softer look; 9999px for pills. |
Shimmer speed (CSS — animation-duration: 1.5s) |
1.5s | Duration of one full cycle. 2s: slower, less distracting; 0.8s: choppy, avoid for long waits. |
Gradient colors (CSS — #1a1a24 / #2a2a34) |
dark gray pair, delta of 16/256 per channel | For light backgrounds, replace with rgba(0,0,0,.06) / rgba(0,0,0,.14) for an adaptive semi-transparent shimmer. For a colored background, use two adjacent shades in the same palette. |
Line widths (CSS — :nth-child(1/2/3) { width }) |
60% / 100% / 80% | Width profile of the lines. 100% / 90% / 60% for a narrowing paragraph; 30% / 100% / 100% to simulate a label followed by two data lines. |
FAQ
#1a1a24 → #2a2a34). fx-0470 structures an editorial block with a title/body hierarchy; fx-0428 represents a row of equal-weight lines — data lists, messages, form fields.animation-delay is set on any line — all start at 0s. The synchrony is intentional: the block reads as a single visual unit rather than a perceptible cascade. To add a stagger, set .skeleton-line:nth-child(1) { animation-delay: 0s }, .skeleton-line:nth-child(2) { animation-delay: .15s }, .skeleton-line:nth-child(3) { animation-delay: .3s }.#1a1a24 = very dark gray) show clearly on a white background, but the shimmer itself (a delta of 16/256 between the two tones) can appear faint. For light backgrounds, replace the gradient with linear-gradient(90deg, rgba(0,0,0,.06) 25%, rgba(0,0,0,.14) 50%, rgba(0,0,0,.06) 75%): the relative contrast stays the same but adapts to any background hue.