webdevpuneet.com

Scroll Velocity Motion Blur — Free Real Velocity-Based CSS Blur Effect

Scroll Velocity Motion Blur · Scroll · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<section class="vb-intro"><h1>Scroll fast ↓</h1><p>Content genuinely blurs in proportion to how fast you're scrolling, then sharpens as you slow down.</p></section>
<section class="vb-list" id="vbList">
  <article class="vb-card"><span>01</span><h3>Momentum</h3><p>Blur amount tracks real pixels-per-frame.</p></article>
  <article class="vb-card"><span>02</span><h3>Inertia</h3><p>Fling the page and watch it smear.</p></article>
  <article class="vb-card"><span>03</span><h3>Friction</h3><p>Slow down and it sharpens back to zero.</p></article>
  <article class="vb-card"><span>04</span><h3>Drift</h3><p>No fixed blur toggle — it's computed live.</p></article>
  <article class="vb-card"><span>05</span><h3>Glide</h3><p>Stop scrolling and blur decays to nothing.</p></article>
  <article class="vb-card"><span>06</span><h3>Coast</h3><p>Try a slow, deliberate scroll versus a flick.</p></article>
</section>
<section class="vb-outro"><p>The blur amount is a live measurement, not a preset.</p></section>
<div class="vb-meter"><span class="vb-meter-label">px/frame</span><span class="vb-meter-value" id="vbMeterValue">0</span></div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Real velocity measurement
Pixels-per-frame computed from actual scroll deltas.
Two-stage smoothing
Velocity and blur each ease, avoiding jitter.
Decays on stop
An rAF loop clears blur even with no final scroll event.
Live velocity meter
A visible readout of the number driving the effect.
GPU-friendly filter
Only the CSS filter property animates.
Frame-normalized speed
Consistent readings regardless of event timing.
No dependencies
Pure vanilla JS and requestAnimationFrame.
Tunable intensity
MAX_BLUR and smoothing factors are simple constants.

About this UI Snippet

Scroll Velocity Motion Blur — Blur That Tracks Real Scroll Speed

Screenshot of the Scroll Velocity Motion Blur snippet rendered live

This isn't a fixed "blur while scrolling, sharp when still" toggle — the blur amount is a genuine, continuously computed function of how fast the page is actually moving. Scroll slowly and the content stays crisp; flick the page hard and it visibly smears with filter: blur(), then eases back to zero as your scroll speed drops. Built entirely with vanilla JavaScript and requestAnimationFrame, no animation library required.

Measuring real velocity, not just "is scrolling"

Every scroll event records the current window.scrollY, compares it against the value from the previous event, and divides by the elapsed time — normalized to a 16.67ms (60fps) frame so the result reads as "pixels moved per frame" regardless of how often the browser actually fires scroll events. That raw instantaneous velocity is smoothed with a simple exponential-moving-average step (velocity += (instVelocity - velocity) * 0.35) so a single noisy event doesn't spike the blur.

A second smoothing pass for the visual blur

The blur amount applied to the content doesn't jump straight to the velocity-derived target either — a requestAnimationFrame loop eases currentBlur toward targetBlur every frame with its own smoothing factor. Two smoothing stages (velocity, then blur) is what gives the effect a soft ramp-up and a soft settle rather than a jittery on/off flicker, while the underlying number driving it all is still a real speed measurement.

Decay when scrolling stops

Because scroll events stop firing entirely once the page is still, the rAF loop separately checks how long it's been since the last event and decays the velocity toward zero if none has arrived in the last couple of frames. Without this, a scroll that stops abruptly (rather than decelerating smoothly, as happens with certain trackpads or a scrollbar drag) would leave the blur stuck at its last value with nothing to bring it back down.

Live velocity readout

A small fixed meter in the corner displays the raw pixels-per-frame velocity number in real time, which makes the relationship between scroll speed and blur amount directly observable rather than something you have to take on faith — useful for tuning MAX_BLUR and the smoothing constants to taste.

Customizing it

Raise MAX_BLUR for a more dramatic smear, tighten BLUR_SMOOTHING for a snappier response, or apply the blur to individual cards instead of the whole list for a more localized effect. Pair it with scroll skew velocity for a combined blur-and-skew treatment, or contrast it with a scroll reveal grid for a calmer entrance.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSAn intro, a card list, a meter, and an outro render.
  2. 2
    Scroll slowlyThe meter stays low and the cards remain sharp.
  3. 3
    Flick-scroll fastThe meter spikes and the cards visibly blur.
  4. 4
    Stop suddenlyBlur eases back to zero even without a final scroll event.
  5. 5
    Watch the meterIt shows the live pixels-per-frame value driving the blur.
  6. 6
    Tune the responseAdjust MAX_BLUR and the smoothing constants to taste.

Real-world uses

Common Use Cases

Kinetic long-scroll editorial
Make fast scrolling feel physical, with blur computed continuously from real pixels-per-frame speed instead of a simple scrolling or still toggle.
Portfolio motion pairing
Pair with scroll skew velocity cards so one effect blurs content and another shears it with momentum.
Product gallery flicks
Blur thumbnails during fast flicks and sharpen them as scrolling slows, with an rAF loop clearing blur even if no final scroll event fires.
Image-heavy feeds
Contrast with a calmer scroll reveal grid, choosing between energetic and restrained approaches for the same content.
Interactive velocity teaching
Use the visible velocity meter as a teaching aid, with two-stage smoothing preventing jitter in both the number and the blur.
Related: Three.js Scroll Shatter & Assemble
See the Three.js Scroll Shatter & Assemble for a related scroll pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Yes. Each scroll event computes the pixel distance moved since the previous event divided by elapsed time, normalized to a 60fps frame, producing a real "pixels per frame" velocity number. That number (after smoothing) directly sets the blur target in pixels, so a fast flick produces measurably more blur than a slow scroll — verifiable by watching the live meter track both.

Raw scroll events are noisy and irregularly timed, so smoothing the velocity first with an exponential moving average avoids a single jumpy event spiking the number. Then easing the applied blur toward that smoothed velocity target, rather than snapping to it every frame, is what gives the blur a soft ramp instead of a flicker — two lightweight smoothing passes instead of one heavier one.

Scroll events simply stop firing once the page is still, so a separate requestAnimationFrame loop tracks how long it has been since the last scroll event and decays the velocity toward zero if none has arrived within about two frames. Without this check, a scroll that stops instantly (rather than decelerating) would leave the last measured blur amount stuck on screen indefinitely.

The scroll listener is passive and does only cheap arithmetic — no DOM reads that trigger layout. The actual style write (filter) happens once per animation frame in the rAF loop rather than once per scroll event, and filter/blur is GPU-composited, so it stays smooth even during a fast, sustained scroll.

Attach the scroll listener and start the rAF loop in a mount effect, storing velocity and currentBlur in refs rather than plain variables so they persist across renders without triggering re-renders themselves; apply the computed blur directly via a ref's style property. Return a cleanup that removes the scroll listener and cancels the animation frame.