16 CSS Gradient Animations 07 / 16
CSS Metallic Shimmer Skeleton Loader
Three skeleton loader patterns — a social card, a list component, and a data table — all sharing a single shimmer keyframe that sweeps a diagonal highlight across each bone element to indicate an active loading state.
The code
<div class="ga-07" data-speed="normal">
<!-- Card skeleton -->
<div class="ga-07__card">
<div class="ga-07__header">
<div class="ga-07__bone ga-07__avatar"></div>
<div class="ga-07__header-lines">
<div class="ga-07__bone ga-07__line ga-07__line--lg"></div>
<div class="ga-07__bone ga-07__line ga-07__line--md"></div>
</div>
</div>
<div class="ga-07__bone ga-07__thumb"></div>
<div class="ga-07__bone ga-07__line ga-07__line--lg"></div>
<div class="ga-07__bone ga-07__line ga-07__line--md"></div>
<div style="display:flex;gap:8px;">
<div class="ga-07__bone ga-07__tag"></div>
<div class="ga-07__bone ga-07__tag" style="width:80px;"></div>
</div>
</div>
<!-- List skeleton -->
<div class="ga-07__list">
<div class="ga-07__list-row">
<div class="ga-07__bone ga-07__icon"></div>
<div class="ga-07__list-lines">
<div class="ga-07__bone ga-07__line ga-07__line--lg"></div>
<div class="ga-07__bone ga-07__line ga-07__line--sm"></div>
</div>
</div>
<div class="ga-07__list-row">
<div class="ga-07__bone ga-07__icon"></div>
<div class="ga-07__list-lines">
<div class="ga-07__bone ga-07__line" style="width:55%;"></div>
<div class="ga-07__bone ga-07__line ga-07__line--sm"></div>
</div>
</div>
<div class="ga-07__list-row">
<div class="ga-07__bone ga-07__icon"></div>
<div class="ga-07__list-lines">
<div class="ga-07__bone ga-07__line ga-07__line--md"></div>
<div class="ga-07__bone ga-07__line" style="width:30%;"></div>
</div>
</div>
<div class="ga-07__list-row">
<div class="ga-07__bone ga-07__icon"></div>
<div class="ga-07__list-lines">
<div class="ga-07__bone ga-07__line" style="width:65%;"></div>
<div class="ga-07__bone ga-07__line ga-07__line--sm"></div>
</div>
</div>
<div style="display:flex;gap:8px;margin-top:4px;">
<div class="ga-07__bone" style="height:34px;width:100%;border-radius:8px;"></div>
</div>
</div>
<!-- Table skeleton -->
<div class="ga-07__table">
<div class="ga-07__thead">
<div class="ga-07__bone ga-07__th" style="width:50%;"></div>
<div class="ga-07__bone ga-07__th" style="width:60%;"></div>
<div class="ga-07__bone ga-07__th" style="width:70%;"></div>
<div class="ga-07__bone ga-07__th" style="width:45%;"></div>
</div>
<div class="ga-07__tbody-row">
<div class="ga-07__td--name">
<div class="ga-07__bone ga-07__td--avatar"></div>
<div class="ga-07__bone ga-07__td" style="flex:1;"></div>
</div>
<div class="ga-07__bone ga-07__td" style="width:55%;"></div>
<div class="ga-07__bone ga-07__td" style="width:70%;"></div>
<div class="ga-07__bone ga-07__td" style="width:40%;"></div>
</div>
<div class="ga-07__tbody-row">
<div class="ga-07__td--name">
<div class="ga-07__bone ga-07__td--avatar"></div>
<div class="ga-07__bone ga-07__td" style="flex:1;width:65%;"></div>
</div>
<div class="ga-07__bone ga-07__td" style="width:80%;"></div>
<div class="ga-07__bone ga-07__td" style="width:50%;"></div>
<div class="ga-07__bone ga-07__td" style="width:60%;"></div>
</div>
<div class="ga-07__tbody-row">
<div class="ga-07__td--name">
<div class="ga-07__bone ga-07__td--avatar"></div>
<div class="ga-07__bone ga-07__td" style="flex:1;width:45%;"></div>
</div>
<div class="ga-07__bone ga-07__td" style="width:65%;"></div>
<div class="ga-07__bone ga-07__td" style="width:45%;"></div>
<div class="ga-07__bone ga-07__td" style="width:75%;"></div>
</div>
</div>
<div class="ga-07__controls">
<button class="ga-07__toggle" data-s="slow">Slow</button>
<button class="ga-07__toggle active" data-s="normal">Normal</button>
<button class="ga-07__toggle" data-s="fast">Fast</button>
</div>
</div> <div class="ga-07" data-speed="normal">
<!-- Card skeleton -->
<div class="ga-07__card">
<div class="ga-07__header">
<div class="ga-07__bone ga-07__avatar"></div>
<div class="ga-07__header-lines">
<div class="ga-07__bone ga-07__line ga-07__line--lg"></div>
<div class="ga-07__bone ga-07__line ga-07__line--md"></div>
</div>
</div>
<div class="ga-07__bone ga-07__thumb"></div>
<div class="ga-07__bone ga-07__line ga-07__line--lg"></div>
<div class="ga-07__bone ga-07__line ga-07__line--md"></div>
<div style="display:flex;gap:8px;">
<div class="ga-07__bone ga-07__tag"></div>
<div class="ga-07__bone ga-07__tag" style="width:80px;"></div>
</div>
</div>
<!-- List skeleton -->
<div class="ga-07__list">
<div class="ga-07__list-row">
<div class="ga-07__bone ga-07__icon"></div>
<div class="ga-07__list-lines">
<div class="ga-07__bone ga-07__line ga-07__line--lg"></div>
<div class="ga-07__bone ga-07__line ga-07__line--sm"></div>
</div>
</div>
<div class="ga-07__list-row">
<div class="ga-07__bone ga-07__icon"></div>
<div class="ga-07__list-lines">
<div class="ga-07__bone ga-07__line" style="width:55%;"></div>
<div class="ga-07__bone ga-07__line ga-07__line--sm"></div>
</div>
</div>
<div class="ga-07__list-row">
<div class="ga-07__bone ga-07__icon"></div>
<div class="ga-07__list-lines">
<div class="ga-07__bone ga-07__line ga-07__line--md"></div>
<div class="ga-07__bone ga-07__line" style="width:30%;"></div>
</div>
</div>
<div class="ga-07__list-row">
<div class="ga-07__bone ga-07__icon"></div>
<div class="ga-07__list-lines">
<div class="ga-07__bone ga-07__line" style="width:65%;"></div>
<div class="ga-07__bone ga-07__line ga-07__line--sm"></div>
</div>
</div>
<div style="display:flex;gap:8px;margin-top:4px;">
<div class="ga-07__bone" style="height:34px;width:100%;border-radius:8px;"></div>
</div>
</div>
<!-- Table skeleton -->
<div class="ga-07__table">
<div class="ga-07__thead">
<div class="ga-07__bone ga-07__th" style="width:50%;"></div>
<div class="ga-07__bone ga-07__th" style="width:60%;"></div>
<div class="ga-07__bone ga-07__th" style="width:70%;"></div>
<div class="ga-07__bone ga-07__th" style="width:45%;"></div>
</div>
<div class="ga-07__tbody-row">
<div class="ga-07__td--name">
<div class="ga-07__bone ga-07__td--avatar"></div>
<div class="ga-07__bone ga-07__td" style="flex:1;"></div>
</div>
<div class="ga-07__bone ga-07__td" style="width:55%;"></div>
<div class="ga-07__bone ga-07__td" style="width:70%;"></div>
<div class="ga-07__bone ga-07__td" style="width:40%;"></div>
</div>
<div class="ga-07__tbody-row">
<div class="ga-07__td--name">
<div class="ga-07__bone ga-07__td--avatar"></div>
<div class="ga-07__bone ga-07__td" style="flex:1;width:65%;"></div>
</div>
<div class="ga-07__bone ga-07__td" style="width:80%;"></div>
<div class="ga-07__bone ga-07__td" style="width:50%;"></div>
<div class="ga-07__bone ga-07__td" style="width:60%;"></div>
</div>
<div class="ga-07__tbody-row">
<div class="ga-07__td--name">
<div class="ga-07__bone ga-07__td--avatar"></div>
<div class="ga-07__bone ga-07__td" style="flex:1;width:45%;"></div>
</div>
<div class="ga-07__bone ga-07__td" style="width:65%;"></div>
<div class="ga-07__bone ga-07__td" style="width:45%;"></div>
<div class="ga-07__bone ga-07__td" style="width:75%;"></div>
</div>
</div>
<div class="ga-07__controls">
<button class="ga-07__toggle" data-s="slow">Slow</button>
<button class="ga-07__toggle active" data-s="normal">Normal</button>
<button class="ga-07__toggle" data-s="fast">Fast</button>
</div>
</div>.ga-07, .ga-07 *, .ga-07 *::before, .ga-07 *::after {
margin: 0; padding: 0; box-sizing: border-box;
}
.ga-07 ::selection { background: rgba(99,102,241,.4); color: #fff; }
.ga-07 {
--bg: #0f111a;
--skel: #1c1e2e;
--shine-from: rgba(255,255,255,0);
--shine-mid: rgba(255,255,255,.07);
--shine-to: rgba(255,255,255,0);
--dur: 1.6s;
width: 100%;
min-height: 100vh;
background: var(--bg);
font-family: system-ui, -apple-system, sans-serif;
display: flex;
align-items: center;
justify-content: center;
gap: 24px;
flex-wrap: wrap;
padding: 48px 24px;
}
/* ── Base skeleton bone ── */
.ga-07__bone {
position: relative;
background: var(--skel);
border-radius: 6px;
overflow: hidden;
}
/* Shimmer wave — single pseudo-element slides across */
.ga-07__bone::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(
105deg,
var(--shine-from) 0%,
var(--shine-from) 35%,
var(--shine-mid) 50%,
var(--shine-to) 65%,
var(--shine-to) 100%
);
background-size: 300% 100%;
background-position: 100% 0;
animation: ga-07-shimmer var(--dur) ease-in-out infinite;
}
@keyframes ga-07-shimmer {
0% { background-position: 150% 0; }
100% { background-position: -50% 0; }
}
/* ── Card skeleton ── */
.ga-07__card {
width: 280px;
background: #13151f;
border: 1px solid rgba(255,255,255,.05);
border-radius: 16px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 14px;
}
.ga-07__avatar { width: 44px; height: 44px; border-radius: 50%; }
.ga-07__line { height: 10px; }
.ga-07__line--lg { width: 70%; }
.ga-07__line--md { width: 50%; }
.ga-07__line--sm { width: 35%; }
.ga-07__thumb { width: 100%; height: 140px; border-radius: 10px; }
.ga-07__tag { width: 60px; height: 22px; border-radius: 999px; }
.ga-07__header {
display: flex;
align-items: center;
gap: 12px;
}
.ga-07__header-lines {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
/* ── List skeleton ── */
.ga-07__list {
width: 280px;
background: #13151f;
border: 1px solid rgba(255,255,255,.05);
border-radius: 16px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 18px;
}
.ga-07__list-row {
display: flex;
align-items: center;
gap: 12px;
}
.ga-07__icon { width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0; }
.ga-07__list-lines {
flex: 1;
display: flex;
flex-direction: column;
gap: 7px;
}
/* ── Table skeleton ── */
.ga-07__table {
width: 560px;
max-width: 100%;
background: #13151f;
border: 1px solid rgba(255,255,255,.05);
border-radius: 16px;
overflow: hidden;
}
.ga-07__thead {
background: rgba(255,255,255,.03);
padding: 14px 20px;
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr;
gap: 16px;
border-bottom: 1px solid rgba(255,255,255,.05);
}
.ga-07__tbody-row {
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr;
gap: 16px;
padding: 14px 20px;
border-bottom: 1px solid rgba(255,255,255,.04);
align-items: center;
}
.ga-07__tbody-row:last-child { border-bottom: none; }
.ga-07__th { height: 8px; border-radius: 4px; }
.ga-07__td { height: 9px; border-radius: 4px; }
.ga-07__td--name { display: flex; align-items: center; gap: 10px; }
.ga-07__td--avatar { width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0; }
/* Toggle loaded state */
.ga-07__controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
z-index: 10;
}
.ga-07 { position: relative; }
.ga-07__toggle {
padding: 6px 16px;
border-radius: 8px;
font-size: .78rem;
font-weight: 700;
cursor: pointer;
border: 1px solid rgba(255,255,255,.1);
background: rgba(255,255,255,.06);
color: rgba(255,255,255,.5);
transition: all .2s;
}
.ga-07__toggle:hover,
.ga-07__toggle.active {
background: rgba(99,102,241,.2);
border-color: rgba(99,102,241,.4);
color: #a5b4fc;
}
/* Fast/slow speed variants */
.ga-07[data-speed="fast"] { --dur: .9s; }
.ga-07[data-speed="slow"] { --dur: 2.8s; }
@media (prefers-reduced-motion: reduce) {
.ga-07__bone::after { animation: none; background-position: -50% 0; }
} .ga-07, .ga-07 *, .ga-07 *::before, .ga-07 *::after {
margin: 0; padding: 0; box-sizing: border-box;
}
.ga-07 ::selection { background: rgba(99,102,241,.4); color: #fff; }
.ga-07 {
--bg: #0f111a;
--skel: #1c1e2e;
--shine-from: rgba(255,255,255,0);
--shine-mid: rgba(255,255,255,.07);
--shine-to: rgba(255,255,255,0);
--dur: 1.6s;
width: 100%;
min-height: 100vh;
background: var(--bg);
font-family: system-ui, -apple-system, sans-serif;
display: flex;
align-items: center;
justify-content: center;
gap: 24px;
flex-wrap: wrap;
padding: 48px 24px;
}
/* ── Base skeleton bone ── */
.ga-07__bone {
position: relative;
background: var(--skel);
border-radius: 6px;
overflow: hidden;
}
/* Shimmer wave — single pseudo-element slides across */
.ga-07__bone::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(
105deg,
var(--shine-from) 0%,
var(--shine-from) 35%,
var(--shine-mid) 50%,
var(--shine-to) 65%,
var(--shine-to) 100%
);
background-size: 300% 100%;
background-position: 100% 0;
animation: ga-07-shimmer var(--dur) ease-in-out infinite;
}
@keyframes ga-07-shimmer {
0% { background-position: 150% 0; }
100% { background-position: -50% 0; }
}
/* ── Card skeleton ── */
.ga-07__card {
width: 280px;
background: #13151f;
border: 1px solid rgba(255,255,255,.05);
border-radius: 16px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 14px;
}
.ga-07__avatar { width: 44px; height: 44px; border-radius: 50%; }
.ga-07__line { height: 10px; }
.ga-07__line--lg { width: 70%; }
.ga-07__line--md { width: 50%; }
.ga-07__line--sm { width: 35%; }
.ga-07__thumb { width: 100%; height: 140px; border-radius: 10px; }
.ga-07__tag { width: 60px; height: 22px; border-radius: 999px; }
.ga-07__header {
display: flex;
align-items: center;
gap: 12px;
}
.ga-07__header-lines {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
/* ── List skeleton ── */
.ga-07__list {
width: 280px;
background: #13151f;
border: 1px solid rgba(255,255,255,.05);
border-radius: 16px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 18px;
}
.ga-07__list-row {
display: flex;
align-items: center;
gap: 12px;
}
.ga-07__icon { width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0; }
.ga-07__list-lines {
flex: 1;
display: flex;
flex-direction: column;
gap: 7px;
}
/* ── Table skeleton ── */
.ga-07__table {
width: 560px;
max-width: 100%;
background: #13151f;
border: 1px solid rgba(255,255,255,.05);
border-radius: 16px;
overflow: hidden;
}
.ga-07__thead {
background: rgba(255,255,255,.03);
padding: 14px 20px;
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr;
gap: 16px;
border-bottom: 1px solid rgba(255,255,255,.05);
}
.ga-07__tbody-row {
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr;
gap: 16px;
padding: 14px 20px;
border-bottom: 1px solid rgba(255,255,255,.04);
align-items: center;
}
.ga-07__tbody-row:last-child { border-bottom: none; }
.ga-07__th { height: 8px; border-radius: 4px; }
.ga-07__td { height: 9px; border-radius: 4px; }
.ga-07__td--name { display: flex; align-items: center; gap: 10px; }
.ga-07__td--avatar { width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0; }
/* Toggle loaded state */
.ga-07__controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
z-index: 10;
}
.ga-07 { position: relative; }
.ga-07__toggle {
padding: 6px 16px;
border-radius: 8px;
font-size: .78rem;
font-weight: 700;
cursor: pointer;
border: 1px solid rgba(255,255,255,.1);
background: rgba(255,255,255,.06);
color: rgba(255,255,255,.5);
transition: all .2s;
}
.ga-07__toggle:hover,
.ga-07__toggle.active {
background: rgba(99,102,241,.2);
border-color: rgba(99,102,241,.4);
color: #a5b4fc;
}
/* Fast/slow speed variants */
.ga-07[data-speed="fast"] { --dur: .9s; }
.ga-07[data-speed="slow"] { --dur: 2.8s; }
@media (prefers-reduced-motion: reduce) {
.ga-07__bone::after { animation: none; background-position: -50% 0; }
}(function() {
const w = document.querySelector('.ga-07');
w.querySelectorAll('.ga-07__toggle').forEach(btn => {
btn.addEventListener('click', () => {
w.querySelectorAll('.ga-07__toggle').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
w.dataset.speed = btn.dataset.s;
});
});
})(); (function() {
const w = document.querySelector('.ga-07');
w.querySelectorAll('.ga-07__toggle').forEach(btn => {
btn.addEventListener('click', () => {
w.querySelectorAll('.ga-07__toggle').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
w.dataset.speed = btn.dataset.s;
});
});
})();How this works
Every skeleton bone is a div with class .ga-07__bone, which sets background: var(--skel) (a dark base colour) and overflow: hidden. The shimmer wave lives entirely on the ::after pseudo-element using background: linear-gradient(105deg, transparent 35%, rgba(255,255,255,.07) 50%, transparent 65%) with background-size: 300% 100%. A single keyframe — @keyframes ga-07-shimmer — moves background-position from 150% 0 to -50% 0, which slides the bright midpoint highlight fully across the bone from right to left. The 105deg angle tilts the wave diagonally so it reads as a metallic gloss rather than a flat sweep.
All bones share the same keyframe declaration but their staggered DOM order means visual variation comes entirely from their different widths and positions. The speed is controlled via a data-speed attribute on the wrapper that maps to CSS custom property values via attribute selectors ([data-speed="fast"] { --dur: .9s }), letting JavaScript update a single attribute rather than touching each bone.
Customize
- Brighten the shimmer by raising the midpoint opacity in
rgba(255,255,255,.07)— try.12for a more visible metallic reflection, or.03for a subtler ghost effect. - Change the shimmer angle from
105degto90degfor a straight left-to-right sweep, or135degfor a steeper diagonal that reads as a more dramatic gloss. - Match the shimmer to your app brand by adding a subtle tint: replace
rgba(255,255,255,.07)withrgba(99,102,241,.12)for a violet-tinted metallic that signals "indigo brand" even in loading state. - Stack multiple skeleton screens by repeating the HTML structure — each bone card shares the same
.ga-07__bone::afterrule so the shimmer automatically applies, keeping CSS overhead minimal. - Add staggered animation delays between bones by adding
animation-delay: Xmsper bone class, creating a cascading shimmer effect rather than all bones lighting up in unison.
Watch out for
overflow: hiddenon.ga-07__boneis mandatory — without it, the::afterpseudo-element (which usesposition: absolute; inset: 0with a background extending beyond the element) will overflow and bleed into adjacent elements.- Setting
border-radiuson a bone withoverflow: hiddenon certain older Safari versions can cause the shimmer to leak through the rounded corners — adding-webkit-mask-image: -webkit-radial-gradient(white, black)as a hack fixes this if needed. - The data-attribute speed switcher uses CSS attribute selectors, not class toggles — ensure the
data-speedattribute matches exactly ("fast","normal","slow") because attribute selectors are case-sensitive in HTML5.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 49+ | 9.1+ | 36+ | 49+ |
All techniques (pseudo-elements, background-size animation, CSS custom properties, data attribute selectors) are universally supported in all modern browsers.