Skip to content

Rules · smooth/*

Smoothness rules

How the page feels after it loads: dropped frames during a scripted scroll, long animation frames, INP of real clicks, shifts after input, animated layout properties, idle rAF loops and reduced-motion handling.

$ void smooth18 rules2 error · 14 warn · 2 infoupdated 16 Sept 2026
  1. smooth/scroll-jankwarnFrames are dropped while scrollingWhen the main thread cannot produce a frame every 16.7 ms, scrolling stutters. Users read this as a cheap, broken site even when load metrics are good.
  2. smooth/long-frames-during-scrollwarnLong animation frames block scrollingLong Animation Frames (LoAF) during scroll show script that delays rendering; the attributed script is the culprit.
  3. smooth/scroll-listener-nonpassivewarnNon-passive wheel/touch listenerA non-passive wheel or touchmove listener forces the browser to wait for JavaScript before it can scroll, so every scroll gesture starts late.
  4. smooth/inp-slowwarnInteractions are slow to respond (INP)Interaction to Next Paint measures the delay from tap/click to the next frame. Above 200 ms the UI feels laggy; above 500 ms it feels broken.
  5. smooth/layout-shift-after-inputwarnLayout shifts long after an interactionShifts that happen more than 500 ms after a tap are not excused by user input and feel like the page is jumping on its own.
  6. smooth/layout-shift-on-scrollwarnLayout shifts while scrollingLazy content that pops in without reserved space shoves the text the reader is looking at.
  7. smooth/animate-layout-propertywarnAnimation of a layout-triggering propertyAnimating width, height, top/left, margin or padding re-runs layout and paint on every frame; box-shadow on large elements repaints large areas. These animations drop frames on phones.
  8. smooth/transition-allwarntransition: alltransition: all animates every property that changes, including layout properties you did not intend, and makes transitions harder to reason about.
  9. smooth/will-change-overuseinfowill-change is applied too broadlyEvery will-change layer costs GPU memory; applying it statically to many elements (or html/body) can make scrolling worse, not better.
  10. smooth/reduced-motion-ignoredwarnAnimations keep running with prefers-reduced-motionPeople with vestibular disorders set reduce motion to avoid nausea and dizziness; infinite or large animations must stop for them (WCAG 2.3.3).
  11. smooth/raf-loop-idlewarnrequestAnimationFrame loop runs while idleA perpetual rAF loop (canvas, WebGL, JS-driven marquee) burns CPU and battery on every frame even when nothing is visible, and competes with scrolling.
  12. smooth/scroll-timeline-no-fallbackerrorContent is invisible without scroll-driven-animation support`animation-timeline: view()/scroll()`, `view-timeline` and `animation-range` have no fallback path: a browser that doesn't implement them (Firefox, at every version through 151) evaluates the enclosing `@supports (animation-timeline: …)` block as false and drops every rule inside it — including the keyframes that would ever make the element visible. If the element's base rule (outside that block) sets `opacity: 0`, `visibility: hidden`, a collapsed scale/mask or an off-screen translate, the content isn't degraded, it's gone — permanently, not just until scrolled into view.
  13. smooth/multiple-webgl-contextswarnMultiple WebGL contextsEach WebGL context has its own GPU state and memory; browsers cap them (≈16) and mobile GPUs struggle with more than one.
  14. smooth/react-commits-on-scrollwarnReact re-renders while the page scrollsScroll position, scroll-spy or in-view state held in React turns every scroll event into a render and commit on the main thread, the same thread that must produce each scroll frame. It costs little on a fast laptop and drops frames on a phone.
  15. smooth/react-wasted-renderswarnReact component re-renders with unchanged propsA component that re-renders when every prop is equal by value, with no state or context change, produced the same output for nothing. Usually the props are rebuilt each render (inline objects, arrays, arrow functions) or a parent re-renders the whole subtree. The check compares values, so treat each hit as a memo candidate to confirm, not proof.
  16. smooth/react-render-stormerrorOne React commit re-renders hundreds of componentsAn update that re-renders more than a few hundred components in a single commit blocks the main thread for the whole render, which shows up as a dropped frame or a slow interaction. It usually means a broad context value or top-level state changed.
  17. smooth/react-idle-commitswarnReact keeps committing while the page is idleTimers, intervals or animation state that re-render React with no input keep the main thread busy and drain battery, and every commit competes with the next scroll or tap. The rendered UI is often not even on screen.
  18. smooth/react-no-namesinfoReact component names are minifiedThe production build minifies component names, so the React findings above name components like `hW`. The DOM selector and snippet in each finding still locate the component, but per-component attribution is harder and there are no render timings.