25 CSS Spinners 21 / 25
Retro TV Static Noise Loader
A miniature CRT television screen filled with flickering monochrome pixel tiles simulates analog static noise, complete with scanline overlay and vignette darkening.
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<div class="sp-21">
<div class="sp-21__tv">
<div class="sp-21__static">
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
</div>
<div class="sp-21__scanline"></div>
<div class="sp-21__glow"></div>
</div>
</div> <div class="sp-21">
<div class="sp-21__tv">
<div class="sp-21__static">
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
<div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div><div class="sp-21__pixel"></div>
</div>
<div class="sp-21__scanline"></div>
<div class="sp-21__glow"></div>
</div>
</div>.sp-21,.sp-21 *,.sp-21 *::before,.sp-21 *::after{box-sizing:border-box;margin:0;padding:0}
.sp-21{
--bg:#0a0a0a;
display:flex;
align-items:center;
justify-content:center;
min-height:100vh;
background:var(--bg);
}
.sp-21__tv{
position:relative;
width:120px;
height:90px;
background:#111;
border-radius:8px;
border:3px solid #333;
overflow:hidden;
box-shadow:0 0 20px rgba(0,0,0,0.8),inset 0 0 10px rgba(0,0,0,0.5);
}
.sp-21__static{
position:absolute;
inset:0;
display:grid;
grid-template-columns:repeat(12,1fr);
grid-template-rows:repeat(9,1fr);
gap:0;
}
.sp-21__pixel{
background:#fff;
animation:sp-21-flicker 0.08s steps(1) infinite;
}
.sp-21__pixel:nth-child(4n+1){animation-delay:0s;opacity:0.9}
.sp-21__pixel:nth-child(4n+2){animation-delay:0.02s;opacity:0.4}
.sp-21__pixel:nth-child(4n+3){animation-delay:0.04s;opacity:0.7}
.sp-21__pixel:nth-child(4n){animation-delay:0.06s;opacity:0.2}
.sp-21__pixel:nth-child(7n){animation-duration:0.12s}
.sp-21__pixel:nth-child(11n){animation-duration:0.06s}
.sp-21__pixel:nth-child(3n){background:#888}
.sp-21__scanline{
position:absolute;
inset:0;
background:repeating-linear-gradient(
to bottom,
transparent 0px,
transparent 3px,
rgba(0,0,0,0.3) 3px,
rgba(0,0,0,0.3) 4px
);
pointer-events:none;
}
.sp-21__glow{
position:absolute;
inset:0;
background:radial-gradient(ellipse,transparent 40%,rgba(0,0,0,0.5) 100%);
pointer-events:none;
}
@keyframes sp-21-flicker{
0%,100%{opacity:var(--o,0.9)}
50%{opacity:0}
}
@media (prefers-reduced-motion: reduce){
.sp-21__pixel{animation:none}
} .sp-21,.sp-21 *,.sp-21 *::before,.sp-21 *::after{box-sizing:border-box;margin:0;padding:0}
.sp-21{
--bg:#0a0a0a;
display:flex;
align-items:center;
justify-content:center;
min-height:100vh;
background:var(--bg);
}
.sp-21__tv{
position:relative;
width:120px;
height:90px;
background:#111;
border-radius:8px;
border:3px solid #333;
overflow:hidden;
box-shadow:0 0 20px rgba(0,0,0,0.8),inset 0 0 10px rgba(0,0,0,0.5);
}
.sp-21__static{
position:absolute;
inset:0;
display:grid;
grid-template-columns:repeat(12,1fr);
grid-template-rows:repeat(9,1fr);
gap:0;
}
.sp-21__pixel{
background:#fff;
animation:sp-21-flicker 0.08s steps(1) infinite;
}
.sp-21__pixel:nth-child(4n+1){animation-delay:0s;opacity:0.9}
.sp-21__pixel:nth-child(4n+2){animation-delay:0.02s;opacity:0.4}
.sp-21__pixel:nth-child(4n+3){animation-delay:0.04s;opacity:0.7}
.sp-21__pixel:nth-child(4n){animation-delay:0.06s;opacity:0.2}
.sp-21__pixel:nth-child(7n){animation-duration:0.12s}
.sp-21__pixel:nth-child(11n){animation-duration:0.06s}
.sp-21__pixel:nth-child(3n){background:#888}
.sp-21__scanline{
position:absolute;
inset:0;
background:repeating-linear-gradient(
to bottom,
transparent 0px,
transparent 3px,
rgba(0,0,0,0.3) 3px,
rgba(0,0,0,0.3) 4px
);
pointer-events:none;
}
.sp-21__glow{
position:absolute;
inset:0;
background:radial-gradient(ellipse,transparent 40%,rgba(0,0,0,0.5) 100%);
pointer-events:none;
}
@keyframes sp-21-flicker{
0%,100%{opacity:var(--o,0.9)}
50%{opacity:0}
}
@media (prefers-reduced-motion: reduce){
.sp-21__pixel{animation:none}
}How this works
A 12×9 grid of small div elements fills the TV screen area. Each cell runs sp-21-flicker — a very fast 0.08s steps(1) animation that snaps opacity between the cell's base value and zero. The steps(1) timing ensures a binary on/off flicker with no interpolation, exactly like analog noise. Four groups of cells (via 4n+1 through 4n) share different base opacities (0.9, 0.4, 0.7, 0.2) and delays, creating varied intensity across the grid.
Two overlay divs add the CRT effect: a repeating linear-gradient scanline pattern at 4px intervals, and a radial vignette gradient darkening the corners. The TV outer frame uses a subtle inset box-shadow for the recessed screen bezel look.
Customize
- Change the noise colour from white/grey to green by setting
--c:#00ff41and--dim:#003b10for a classic night-vision monitor look. - Increase the grid to 16×12 columns/rows and reduce cell size proportionally for finer, more realistic noise grain.
- Add a CSS animation on the entire
.sp-21__tvthat occasionally shiftstranslateXby 2-3px for a signal distortion effect. - Remove the scanline overlay div and replace the
background:#fffcells withbackground:var(--c)to create a coloured noise channel. - Add a
filter:contrast(1.5) brightness(0.8)on the TV element to punch up the noise contrast.
Watch out for
steps(1)at0.08screates very frequent repaint events — 108 grid cells each repainting independently can easily overwhelm the paint budget on mobile; reduce cell count or increase animation duration for mobile-first contexts.- The
animation-durationvariation via7nand11nselectors only works as intended when those indices exist in the DOM; the grid must have enough cells for the pattern to be visible. opacityanimations create stacking context changes at the composited layer level — 108 simultaneous stacking context creations may cause rendering lag; consider Canvas or WebGL for high-quality static noise at scale.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 60+ | 12+ | 60+ | 60+ |
CSS grid and steps() timing widely supported; performance-sensitive on mobile — test cell count.