Typed Halftone Background Drift
A procedural halftone background that registers dot offset and stop values with @property so the radial-gradient pattern drifts smoothly instead of jumping between gradient strings.
A procedural halftone background that registers dot offset and stop values with @property so the radial-gradient pattern drifts smoothly instead of jumping between gradient strings.
Background / @property / halftone
Three procedural halftone backgrounds register typed custom properties so dot size, phase, and stop values interpolate instead of jumping.
@property · phase drift
Typed offset variables move the dot lattice smoothly.
Dot radius · registered length
Register the radius value so density changes interpolate.
Layered dots · independent phase
Layered radial gradients use independent typed offsets.
A typed halftone background registers dot offset variables with @property, then drifts radial-gradient dot layers without swapping whole background strings.
<div class="halftone-panel"><strong>Halftone</strong></div><style>6@property --dot-x {syntax: '<length>';inherits: false;initial-value: 0px;}@property --dot-y {syntax: '<length>';inherits: false;initial-value: 0px;}.halftone-panel {--dot-x: 0px;--dot-y: 0px;width: 18rem;aspect-ratio: 16 / 9;display: grid;place-items: center;border-radius: 1rem;color: white;background:26radial-gradient(circle at calc(10px + var(--dot-x)) calc(10px + var(--dot-y)), rgba(103,232,249,.86) 0 3px, transparent 4px),radial-gradient(circle at calc(18px - var(--dot-x)) calc(18px - var(--dot-y)), rgba(244,114,182,.58) 0 2px, transparent 3px),#0f172a;29background-size: 24px 24px, 18px 18px, auto;animation: halftone-drift 5s linear infinite;}@keyframes halftone-drift {33to { --dot-x: 12px; --dot-y: 8px; }}35@media (prefers-reduced-motion: reduce) {.halftone-panel { animation: none; }}</style>
Unregistered custom properties tend to step. Registered length values can interpolate smoothly.
It gives custom properties a type, so the browser can interpolate offsets smoothly instead of snapping between string values.
Dense enough to read as halftone, but not so dense that text loses contrast. Increase the solid overlay before increasing motion.
Changing background-size makes dot spacing shimmer. A fixed grid with offset drift keeps the texture stable.
Usually no. Animate offset or a typed scale variable; changing background-size can shimmer and distract from foreground content.
Different expression methods such as offset drift, density shimmer, or scale pulse. Color-only domain changes are not enough.
Pin the background at a balanced frame and keep foreground contrast. Do not replace the drift with a new animated fallback.
Same 4.8s cycle, same radial-gradient dot layers, same @property --dot-x/--dot-y offset drift on both — the dot positions interpolate identically. BEFORE keeps the palette frozen at the gradient's authored colors. AFTER registers --dot-hue as a typed angle and animates it through filter: hue-rotate(); because the property is typed, the browser tweens 0deg → 360deg smoothly while the offset drift continues on its own animation. Two Houdini-interpolated streams running in parallel on the same panel.
The base recipe registers --dot-x and --dot-y as typed lengths so the dot offset can interpolate smoothly through the Houdini @property mechanism. Production halftone effects ALSO drift their palette over time — but a naive color swap re-paints the entire gradient string each frame and stops interpolating. Register one more typed property — --dot-hue as an angle — and feed it into a filter: hue-rotate() on the same panel. The hue cycle runs on its own keyframe alongside the existing offset drift; both keep the typed-interpolation guarantee the base teaches. Same @property pattern, one more registered value extending the chain to color.
Append these rules inside the <style> block from the base snippet above.
/* Advanced: typed hue cycle — extends the base recipe.Same @property mechanism the base uses for --dot-x/--dot-y,extended with a registered angle for --dot-hue. The hue is fedinto filter: hue-rotate() and the animation list grows by onekeyframe — the browser interpolates the angle smoothly because theproperty is typed, exactly like the offset interpolation the baserelies on. No string-swap fallback. */@property --dot-hue {syntax: '<angle>';inherits: false;initial-value: 0deg;}.halftone-panel {--dot-hue: 0deg;filter: hue-rotate(var(--dot-hue));animation:halftone-drift 5s linear infinite,halftone-hue 8s linear infinite;}@keyframes halftone-hue {to { --dot-hue: 360deg; }}@media (prefers-reduced-motion: reduce) {.halftone-panel { animation: none; filter: hue-rotate(0deg); }}
Typed halftone drift turns a procedural dot field into an animatable surface. The key is that the dots are not a bitmap and the animation is not swapping entire gradient declarations. radial-gradient() layers define the halftone, while @property exposes numeric controls for offset, radius, density, or angle.
Use it for editorial headers, poster-like cards, small branded backgrounds, and data-adjacent surfaces where the dot structure is part of the visual language. It is strongest when the viewer should notice the printing or screen pattern itself. Avoid it behind long text, dense controls, or small numeric labels unless a stable overlay preserves contrast.
The background is made from repeated radial gradients whose positions and sizes are driven by custom properties. @property registers values with syntax such as <length>, <percentage>, or <angle>, allowing keyframes to move numeric controls instead of a whole gradient string.
A new showcase example should change the expression method: offset drift, density shimmer, scale pulse, and duotone phase are distinct. Merely recoloring the same dot drift for another domain is not enough. Also watch paint cost at large sizes; procedural backgrounds can still repaint if the animated properties affect the gradient surface every frame.
The halftone is decorative. Keep text outside the moving dot contrast or behind a stable surface, and test the highest-density frame as well as the rest frame. Reduced motion should stop both dot drift and density shimmer while leaving a static halftone that still fits the design.
Typed halftone drift treats dot spacing and offsets as animatable numeric values. Registering custom properties lets the browser interpolate the procedural background controls instead of swapping a whole radial-gradient string at keyframe boundaries.
The important design rule is expression method first. Dot scale, offset drift, and density shimmer are different halftone behaviors; changing only the color or domain label is not a new pattern. Keep text over the dots inside a contrast-tested surface.
Typed variables also make inspector controls honest. If a slider claims to control phase, radius, or density, it should update a registered value that visibly interpolates, not toggle a class that jumps between two hardcoded backgrounds.
Large halftone fields can still repaint, so keep them scoped. Use the effect for compact surfaces, cap density at small sizes, and verify that the reduced-motion frame does not create a noisy optical texture behind content.