-
Notifications
You must be signed in to change notification settings - Fork 15
Description
Description
When Optimole's JS page profiler measures an image on a desktop screen (e.g. 1440px wide), it stores srcset entries capped at that container width. Visitors on wider screens (e.g. 1750px) then receive a srcset whose largest 1x entry is 1440px. The browser has no larger 1x size available, so it stretches the 1440px image to fill 1750px, causing visible blur — even when the original source image is 2560px wide with plenty of quality available.
Expected behaviour: The srcset should include 1x entries up to the image's natural width (e.g. 1920w, 2560w), regardless of what viewport width the profiling visit happened on.
Current behaviour: The srcset is hard-capped at the img.offsetWidth at the time of profiling. Any breakpoint wider than the profiling container is silently skipped for 1x DPR.
Step-by-step reproduction instructions
- Upload a large image (e.g. 2560×1440px) and place it as a full-width hero on any page.
- Ensure Optimole lazyload / page profiler is active.
- Visit the page on a 1440px wide non-retina screen (DPR = 1) — this triggers the profiling run and stores the srcset.
- Now visit the same page on a 1750px+ wide non-retina screen (DPR = 1).
- Inspect the served image URL or open DevTools → Network → filter by image. Observe the image is served at
w:1440despite the viewport being 1750px. - The image appears visibly blurry/stretched because 1440px is being upscaled to fill 1750px.
Screenshots / code snippet
Noticed here: https://secure.helpscout.net/conversation/3248131428/484598
The root cause is in assets/js/modules/srcset-detector.js inside _generateResponsiveSizes():
// Current code (line ~446):
if (dprValue === 1 && targetWidth > currentWidth) {
return; // ← skips 1920w and 2560w entries when profiled on a 1440px container
}currentWidth is read from img.offsetWidth — the CSS-rendered size at profiling time. For a full-width hero on a 1440px screen, this is 1440px. Any breakpoint wider than that (e.g. DESKTOP_LARGE: 1920, DESKTOP_XL: 2560) is skipped for DPR=1, so they are never stored in the global srcset profile.
The stored srcset ends up being e.g.: 640w, 960w, 1200w, 1440w, 2880w (2x only)
A 1750px DPR=1 visitor receives this srcset, has no 1x entry above 1440w, and the browser either stretches 1440w → blurry, or picks the 2880w 2x entry (which wastes bandwidth).
Proposed fix — one line change:
// Fixed: cap against naturalWidth instead of currentWidth
if (dprValue === 1 && targetWidth > naturalWidth) {
return;
}This ensures that 1x srcset variants are generated for all breakpoints up to the image's actual pixel width, regardless of how wide the screen was during profiling.
Additional notes:
- Setting
width="2560"as an HTML attribute on the<img>tag does not work around this, because the profiler readsimg.offsetWidth(CSS layout), not the HTML attribute. CSSmax-width: 100%overrides the HTML attribute andoffsetWidthstays at container width. - The profiled srcset data is stored under
DEVICE_TYPE_GLOBALinProfile.php— meaning a single profiling visit on any desktop screen sets the srcset ceiling for all desktop visitors, regardless of their actual viewport width.
Is this a regression?
No — this appears to be a design limitation in the srcset profiler that has always been present.