Image sequence scroll animation lagging on mobile? 9 fixes
Your scroll image sequence is smooth on desktop but stutters, goes blank, or reloads on phones. Here are the 9 fixes that actually work, from frame count and decoded memory to mobile frame sets and loading strategy, with a WordPress checklist.
Image sequence scroll animation lagging on mobile? 9 fixes
Short answer: mobile lag in a scroll image sequence almost always comes from the frames themselves: too many, too large, decoded at full resolution into the phone's limited memory, and loaded all at once. Use fewer frames, a separate smaller mobile frame set, JPG or WebP at sensible quality, progressive loading, and canvas drawing tied to animation frames rather than raw scroll events. The nine fixes below cover each cause, in the order that usually gives the biggest win.
If your animation is fine on a laptop and falls apart on a phone, you're not alone. It's the single most common problem we see from people building Apple-style scroll pages, whether they wrote the code by hand, generated it with an AI assistant, or used a plugin. The good news: it's fixable, and you rarely have to give up the effect.
Why do image sequences lag on phones but not on desktop?
A scroll image sequence is a folder of numbered images (frame_0001.webp, frame_0002.webp...) drawn onto a <canvas> one at a time as you scroll. It's a simple idea, but it asks three things of the device:
- Download every frame (network and data).
- Decode each frame into raw pixels (CPU and memory).
- Draw the right frame fast enough to keep up with your thumb (GPU and main thread).
A desktop has a fast connection, gigabytes of spare memory, and a strong CPU. A phone has a fraction of that memory available to a single browser tab, a variable connection, and an operating system that will happily kill a tab that uses too much. The same sequence that feels instant on desktop can be several times too heavy for mobile.
Fix 1: Use fewer frames
More frames don't automatically mean smoother. Smoothness comes from how many frames change per unit of scroll, not the total count. For a typical hero animation, 60–350 frames is usually plenty. Around 10–20px of scroll per frame feels fluid; tighter than that and most visitors can't see the difference, but their phone feels it.
If you exported every frame of a 10-second, 30fps clip, that's 300 frames. Dropping to every second or third frame often looks identical on scroll when there is no fast movement.
Read more in how many frames a scroll animation needs.
Fix 2: Make each frame smaller (dimensions first, then format)
Frame dimensions matter more than most people think. A 1920×1080 frame shown in a 390px-wide phone viewport is wasted pixels. Export at the size the frame is actually displayed, with a sensible allowance for screen density (capping canvas DPR at 1.5–2×; see Fix 5 for mobile sets).
Then pick a compact format. For most sequences today, JPG or WebP at moderate quality is the best default: small files, fast decode, and universal support in current browsers. Avoid PNG and use WebP for transparency, and even then test the size. A useful target is roughly 15–90KB per frame for a hero sequence.
Format comparison: WebP vs PNG vs JPG for image sequences.
Fix 3: Understand decoded memory (width × height × 4)
This is the part almost nobody explains. File size is what you download; decoded size is what the browser holds in memory to draw the frame. A decoded image takes roughly:
width × height × 4 bytes (one byte each for red, green, blue, alpha)
So:
- One 1920×1080 frame ≈ 8.3 MB decoded, no matter whether the file was 40KB or 400KB.
- 150 of those ≈ 1.2 GB if they're all kept decoded at once.
- The same 150 frames at 750×1334 ≈ 4 MB each, about 600 MB total. Still heavy.
- At 540×960 ≈ 2 MB each, about 310 MB total.
That's why compressing the file harder doesn't fix mobile crashes on its own. You have to reduce dimensions and how many frames are decoded at the same time.
Fix 4: Don't let mobile address bar resizes trash your layout
On mobile Safari and Chrome, scrolling down automatically hides the browser's top address bar and bottom navigation toolbar; scrolling up brings them back. Every time this happens, the browser window height changes by 60–100px.
If your animation setup isn't prepared for this, two problems ruin your page:
- Layout jump (CLS): If your sticky section or canvas container uses CSS
100vh(or100dvh), its height changes dynamically mid-scroll, causing visible jerking and content jumps. - Performance thrashing: If your JavaScript recalculates the canvas dimensions, scroll triggers, or timeline on every window
resizeevent, the browser fires resize handlers while the user is actively scrolling. Tearing down and rebuilding scroll calculations mid-gesture destroys frame rates.
How to fix it:
- Filter window
resizeevents in JS: Only recalculate your layout when the viewport width changes (such as device rotation / orientation change). Ignore vertical-only height changes caused by the address bar:let lastWidth = window.innerWidth; window.addEventListener('resize', () => { // Ignore height-only resizes from mobile URL bar collapsing if (window.innerWidth === lastWidth) return; lastWidth = window.innerWidth; recalculateScrollAnimation(); });
Fix 5: Serve a separate portrait / mobile frame set
A landscape 16:9 sequence on a portrait phone is usually either tiny or cropped, and you're shipping pixels nobody sees. One of the clean fixes is a second frame set made for mobile: portrait or square crop, smaller dimensions, and often fewer frames.
This also solves composition: you can reframe the subject so it fills a phone screen properly instead of shrinking a desktop shot.
In Scrollsequence v2, sequences support multi-resolution packaging, allowing you to deliver a dedicated, lower-resolution image set specifically tailored to phone viewports.
Fix 6: Don't preload everything; load progressively
The classic tutorial approach is "load all 300 images, then start." On mobile that means a long blank wait, a big data bill, and a memory spike.
Better strategies:
- Load the first frame immediately so something is visible at once (and it can be your poster image).
- Load a sparse pass first (every 4th or 8th frame) so scrubbing works early at lower smoothness, then fill in the gaps.
- Start loading when the section approaches the viewport, not on page load, if the animation isn't at the top.
- Release or avoid keeping every frame decoded at once on low-memory devices.
Scrollsequence implements this with a smart sparse preload algorithm: Frame 0 loads first with atomic priority so the poster image is immediate, followed by a distributed pass across the sequence so visitors can scrub right away. The remaining frames fill in progressively in the background without flooding memory.
Fix 7: Stop the blank canvas on fast scroll
If you flick fast and the canvas flashes blank or white, the code is trying to draw a frame that hasn't loaded or decoded yet, and clearing the canvas before it has anything to draw.
Fixes:
- Never clear the canvas unless you have a frame to draw. If the target frame isn't loaded yet, keep drawing the nearest loaded neighbor frame instead of flashing blank or white.
- Draw inside
requestAnimationFrame, not on every rawscrollevent. Scroll events can fire hundreds of times per second; you only need one canvas draw per display refresh. - The "pre-decode" dead end (
createImageBitmap/img.decode()): Many tutorials and AI code generators attempt to fix stutter by pre-decoding upcoming frames withcreateImageBitmap()orimg.decode(). On mobile, this is a trap:createImageBitmap()forces uncompressed RGBA bitmap buffers directly into RAM. Holding dozens of uncompressed bitmaps in memory will quickly exhaust iOS Safari's tab memory limit and crash the page (see Fix 8).img.decode()is designed to prevent DOM jank when inserting an<img>tag into the document; it doesn't prevent canvas draw cost or memory bloat.- The true cure for canvas flashing on fast scrolls is nearest-neighbor fallback, not forcing ahead-of-time bitmap allocations.
This is the same family of issues covered in why your AI-built scroll animation lags.
Fix 8: Know when iOS Safari is killing the tab
If the page reloads by itself on an iPhone, or Safari shows "A problem repeatedly occurred," that isn't lag: iOS ran out of memory for the tab and killed it. It's the extreme end of Fix 3. The cure is the same set of fixes (fewer, smaller frames, a mobile set, not holding everything decoded), but it deserves its own checklist: iPhone Safari crashes or reloads on my scroll animation.
Fix 9: Protect LCP and Core Web Vitals
A heavy sequence at the top of a page can hurt Largest Contentful Paint (the main content takes too long to appear) and Interaction to Next Paint (the main thread is busy decoding images). Practical steps:
- Give the section a real poster image (the first frame) that loads fast, so LCP isn't waiting on the sequence.
- Don't block the page on loading frames; load them after the first paint.
- Keep your headline and key text as real HTML, not baked into the frames. That helps both search engines and AI assistants read the page.
- Reserve the section's height so the layout doesn't jump (CLS).
Full checklist: do scroll animations hurt SEO?
WordPress-specific: why "it's just a shortcode" can still be heavy
In WordPress, you'll usually place a sequence with a Gutenberg block or, in builders like Elementor, Bricks, Divi or Oxygen, a shortcode such as [scroll-sequence id="..."]. The shortcode is tiny, but what it renders still loads your frames. Wrapping it in a builder widget, a hidden tab, or a "desktop only" container doesn't automatically stop the images from downloading.
Because page builder responsive toggles (like Elementor's "Hide on Mobile") typically apply display: none in CSS rather than removing the DOM nodes from server output, the script and images will still initialize and download in the background. If you want to disable a sequence on phones, use conditional server-side rendering or supply a tiny mobile frame set instead.
WordPress-specific things to check:
- Caching/CDN helps a lot: frames are static files and should be served from a CDN with long cache headers.
- Don't stack too many sequences. Five heavy sequences on one page multiplies every problem above.
- Avoid scrubbing MP4 instead. It feels like the lighter option but stutters badly on scroll, especially on mobile. Why: video on scroll: why scrubbing stutters (MP4 vs image sequence).
Mobile scroll-sequence checklist
Copy this and work through it top to bottom:
- Hero sequence uses roughly 60–350 frames, not every frame of the source video
- Frames exported and rendered near display size, not original video size
- JPG or WebP at moderate quality; avoid PNG unless transparency is required
- Average frame around 15–90KB
- Decoded memory estimated (width × height × 4 × frames held) and sane for phones
- Canvas DPR capped around 1.5–2
- Pinned section uses stable units (100svh or locked height) and resize handlers ignore address bar height changes
- Separate portrait / mobile frame set (smaller, maybe fewer frames)
- First frame visible immediately; rest load progressively
- Drawing in
requestAnimationFrame; canvas never cleared without a frame to draw - Tested on a real iPhone with Safari, not only the desktop emulator
- Poster image, real HTML headings, reserved height for Core Web Vitals
- Frames served from CDN, excluded from conflicting optimization plugins
- One heavy sequence per page, ideally
How Scrollsequence handles this
You can do every fix above by hand with ffmpeg and your own canvas code. If you'd rather not, Scrollsequence is a WordPress plugin built around exactly these problems: it turns any video into a scroll image sequence (with the free vid2ssq converter, either npx scrollsequence vid2ssq or built into wp-admin in v2), supports multi-resolution sequences, and works as a native Gutenberg block or a shortcode in Elementor, Bricks, Divi and Oxygen. There's a free version to try on your own footage.
You can test the core canvas engine with the free version of Scrollsequence on scrollsequence.com or from the WordPress plugin repository, complete with the free vid2ssq converter. Multi-resolution responsive packaging, visual canvas layout, and 3D WebGL depth maps are available in the Pro edition.
Related reading
- How many frames does a scroll animation need?
- iPhone Safari crashes or reloads on my scroll animation
- WebP vs PNG vs JPG for image sequences
- Why your AI-built scroll animation lags
- Video on scroll: why scrubbing an MP4 stutters
FAQ
Why is my scroll animation smooth on desktop but laggy on my phone? Phones have far less memory per browser tab and slower decode. The same full-resolution frames that a laptop can hold decoded will overwhelm a phone. Smaller frames and a mobile frame set fix most cases.
Will converting to WebP fix mobile lag? It helps download time, but not decoded memory. A 1920×1080 frame takes about 8 MB in memory whether it's WebP, JPG or PNG. Reduce dimensions and frame count too.
Should I just use an MP4 video on mobile instead? Playing a video normally is fine. Scrubbing a video with scroll is not: browsers aren't built to seek video that fast, so it stutters. An image sequence with a light mobile set is usually smoother.
How many frames is too many for mobile? There's no single limit, but if frames × width × height × 4 adds up to several hundred MB, you're at risk. A thinner mobile set of 40–100 smaller frames is a safe starting point.
Does hiding the animation on mobile in my page builder stop it loading? Not necessarily. Many builders hide elements with CSS, and the images can still download. Check the network tab on a phone-sized viewport, or use a dedicated mobile frame set instead.
Read more
iPhone Safari crashes or reloads on my scroll animation: why and how to fix it
If your scroll image sequence makes iPhone Safari reload the page or show 'A problem repeatedly occurred', the tab is running out of memory. Here's why decoded frames cause it and how to fix it.
How many frames does a scroll animation need? (and how big should each be)
Rules of thumb for scroll image sequences: about 60–150 frames for a hero, 15–20px of scroll per frame, roughly 15–40KB per WebP frame, and a thinner mobile set. When more frames help and when they hurt.

From video to scroll animation - DIY with ffmpeg, or free with Scrollsequence vid2ssq
Scrubbing an MP4 with currentTime stutters. The reliable pattern is frames on a canvas. Here's the generic DIY path, then what free npx scrollsequence vid2ssq adds (multi-size tiers, optional depth maps and vision for agents).