How to Build a Skeleton Screen That Doesn't Cause Layout Shift
Create high-performance skeleton loading screens: exact layout mirroring, CSS gradient shimmer effects, CLS prevention, and transitioning to loaded content.
Core Takeaway
A well-designed skeleton screen matches the exact typography, padding, and aspect ratio of incoming content to prevent Cumulative Layout Shift (CLS). Use a linear-gradient shimmer sweeping across a neutral gray background with transform or background-position animations on a 1.5s loop. Swap to real content with a subtle 150ms crossfade.
Why skeleton screens beat spinner loaders
A blank screen with a central spinner increases perceived load time because it gives no spatial context. A skeleton screen provides an instant mental model of where text, images, and buttons will appear, making the wait feel shorter.
Eliminating Cumulative Layout Shift (CLS)
If a skeleton box is 120px tall but the incoming card renders at 200px, the page jumps abruptly, damaging Core Web Vitals. Match font sizes, line heights, and aspect ratios strictly.
- Match skeleton box dimensions 1:1 with real content containers
- Use aspect-ratio on image skeleton placeholders
- Sweep shimmer gradient from left to right over 1.2 to 1.8 seconds
- Avoid animating width or height; use background-position or opacity
The CSS shimmer implementation
A subtle highlight moving from left to right suggests continuous background activity. Implement this using a repeating linear-gradient with background-size: 200% and animate background-position.
Handling reduced motion
Continuous shimmering can cause fatigue or distraction. Under prefers-reduced-motion, freeze the shimmer gradient into a static neutral tone or a very slow, gentle opacity pulse.
Production Implementation Snippet
/* CSS Shimmer effect */
.skeleton {
background: linear-gradient(
90deg,
#e5e7eb 25%,
#f3f4f6 50%,
#e5e7eb 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: 6px;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
.skeleton {
animation: none;
background: #e5e7eb;
}
}Key Principles to Remember
- Mirror exact dimensions of final content to achieve zero layout shift (CLS)
- Animate a subtle gradient shimmer across 1.5 seconds
- Crossfade to final content smoothly rather than popping instantly
- Disable continuous motion when prefers-reduced-motion is active
Frequently Asked Questions
Sources
- Skeleton Screens and Perceived Performance — Nielsen Norman Group
- Cumulative Layout Shift (CLS) — web.dev