25 CSS Spinners21 / 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.
Published
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;
}
}Here's a working CSS Spinner from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Retro TV Static Noise Loader
Source: https://codefronts.com/motion/css-spinner-designs/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.
## HTML
```html
<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>
```
## CSS
```css
.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;
}
}
```Here's a working CSS Spinner from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Retro TV Static Noise Loader
Source: https://codefronts.com/motion/css-spinner-designs/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.
## HTML
```html
<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>
```
## CSS
```css
.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.
Make it yours
- 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.
Gotchas — read before shipping
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.