Two polka dot layers drift diagonally in opposite directions, soft large dots behind and small crisp ones in front, for a light, playful parallax. Radial gradient tiles moved by one tile per loop.
Also known as: animated polka dots css, moving dots pattern css, dotted background animation.
<div class="bgx-polka-dots" aria-hidden="true"></div>
.bgx-polka-dots {
--c: var(--bgx-color, #3b82f6);
font-size: var(--bgx-size, 16px);
position: absolute;
inset: 0;
overflow: hidden;
--gap: 3em;
--fine: 2em;
background: color-mix(in srgb, var(--c) 10%, #fff);
}
.bgx-polka-dots::before,
.bgx-polka-dots::after {
content: "";
position: absolute;
inset: -4em;
}
.bgx-polka-dots::before {
--dot: radial-gradient(circle, color-mix(in srgb, var(--c) 30%, transparent) 0.62em, transparent 0.66em);
background:
var(--dot) 0 0 / var(--gap) var(--gap),
var(--dot) calc(var(--gap) / 2) calc(var(--gap) / 2) / var(--gap) var(--gap);
animation: bgx-polka-dots-back 7s linear infinite;
}
.bgx-polka-dots::after {
background: radial-gradient(circle, color-mix(in srgb, var(--c) 85%, transparent) 0.16em, transparent 0.19em) 0 0 / var(--fine) var(--fine);
animation: bgx-polka-dots-front 5s linear infinite;
}
@keyframes bgx-polka-dots-back {
to { transform: translate(var(--gap), var(--gap)); }
}
@keyframes bgx-polka-dots-front {
to { transform: translate(calc(var(--fine) * -1), var(--fine)); }
}
@media (prefers-reduced-motion: reduce) {
.bgx-polka-dots, .bgx-polka-dots *, .bgx-polka-dots::before, .bgx-polka-dots::after, .bgx-polka-dots *::before, .bgx-polka-dots *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--bgx-color on the element or a parent.
Currently previewing #3b82f6.--bgx-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.