Animate SVG Gradients for Shimmer Skeleton Loaders
A shimmering skeleton loader provides visual feedback to users while content is loading in the background. By utilizing SVG linear gradients and animating their coordinate offsets, you can build lightweight, resolution-independent placeholders that smoothly sweep light across shapes. This guide explains how to define an SVG linear gradient, configure the highlight stops, and animate the gradient across your elements using both native SVG animation (SMIL) and modern CSS techniques.
Understanding the Shimmer Mechanism
A shimmer effect relies on a three-stop
<linearGradient>: 1. Base Color: The
default placeholder color (e.g., #e0e0e0). 2.
Highlight Color: A slightly lighter tone placed in the
middle (e.g., #f5f5f5). 3. Base Color: The
default placeholder color at the end to create a seamless loop.
To achieve movement, the gradient’s horizontal coordinate attributes
(x1 and x2) or translation properties are
animated continuously from left to right.
Method 1: Pure SVG with
SMIL <animate>
The most self-contained method uses SVG’s native SMIL
(Synchronized Multimedia Integration Language) elements.
This keeps the animation contained inside the SVG file without relying
on external CSS.
<svg viewBox="0 0 400 130" width="100%" height="130" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- Define the gradient with a base width of 100% -->
<linearGradient id="shimmer" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#e0e0e0" />
<stop offset="50%" stop-color="#f0f0f0" />
<stop offset="100%" stop-color="#e0e0e0" />
<!-- Animate x1 and x2 horizontally -->
<animate
attributeName="x1"
from="-100%"
to="100%"
dur="1.5s"
repeatCount="indefinite"
/>
<animate
attributeName="x2"
from="0%"
to="200%"
dur="1.5s"
repeatCount="indefinite"
/>
</linearGradient>
</defs>
<!-- Apply the animated gradient fill to your skeleton shapes -->
<circle cx="40" cy="40" r="30" fill="url(#shimmer)" />
<rect x="90" y="20" rx="4" ry="4" width="250" height="16" fill="url(#shimmer)" />
<rect x="90" y="45" rx="4" ry="4" width="180" height="12" fill="url(#shimmer)" />
<rect x="10" y="90" rx="4" ry="4" width="330" height="12" fill="url(#shimmer)" />
</svg>How It Works:
x1shifts from-100%to100%, whilex2shifts from0%to200%.- The distance between
x1andx2remains constant (100%), keeping the highlight width consistent throughout the sweep. repeatCount="indefinite"ensures a seamless, infinite loop.
Method 2: Animating via CSS Keyframes
If you prefer controlling the animation globally or managing themes dynamically, you can manipulate the gradient stops or coordinate transforms using CSS.
1. The SVG Markup
<svg class="skeleton-loader" viewBox="0 0 400 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="css-shimmer" x1="0" y1="0" x2="1" y2="0">
<stop class="stop-base" offset="0%" />
<stop class="stop-highlight" offset="50%" />
<stop class="stop-base" offset="100%" />
</linearGradient>
</defs>
<rect x="0" y="0" rx="6" ry="6" width="400" height="100" fill="url(#css-shimmer)" />
</svg>2. The CSS Animation
.skeleton-loader linearGradient {
--start: -100%;
--end: 200%;
}
.stop-base {
stop-color: #e5e7eb;
}
.stop-highlight {
stop-color: #f3f4f6;
}
@keyframes shimmer-sweep {
0% {
x1: -100%;
x2: 0%;
}
100% {
x1: 100%;
x2: 200%;
}
}
.skeleton-loader linearGradient {
animation: shimmer-sweep 1.6s infinite linear;
}Best Practices for Smooth Performance
- Gradient Contrast: Keep the highlight stop color close to the base color (a 5% to 10% brightness difference). High-contrast highlights cause harsh flickers rather than smooth glimmers.
- Aspect Ratio Preservation: Always include a
viewBoxon the root<svg>tag. This allows your skeleton shapes and the gradient sweep to scale proportionally across different device sizes. - Subtle Easing: While
lineartiming produces consistent movement,ease-in-outtiming can provide a softer, more natural transition as the highlight passes across the view.