Use passive scroll listeners
Mark touch and wheel listeners passive unless they cancel scroll.
From nextjs-pagespeed.
What the scroll waits for
Press Flick, then change the handler cost.
passive: falseBad
passive: trueGood
Scroll the real thing
Scroll each list with a wheel or finger.
passive: falseBad
0 events
passive: trueGood
0 events
Main-thread frame timeIdle
list.addEventListener("wheel", onWheel, { passive: true });
list.addEventListener("touchmove", onTouchMove, { passive: true });
canvas.addEventListener("wheel", zoom, { passive: false });
Stop scroll chaining with CSS
Scroll each list past its end.
JS: preventDefaultBad
Page leaked: 0
wheel, { passive: false }CSS: overscrollGood
Page leaked: 0
.panel { overscroll-behavior: contain; }
.canvas { touch-action: none; }
.slider { touch-action: pan-y; }
Why it matters, pros and cons
Why it matters
A non-passive listener makes scrolling wait for JavaScript every time.
Pros
- Scroll starts next frame, however busy JS is.
- One option flag, same handler body.
- React already attaches wheel and touch passively.
Cons
- Passive listeners cannot cancel custom zoom or drag.
- The handler itself gets no cheaper.
- No effect on the
scrollevent itself.