← back to Dw Photo Capture
5x sweep: lazy-load grid thumbnails (IntersectionObserver) — grid used CSS background-images (can't use loading=lazy) so a big filter loaded 100s of images at once. Now bg applies only on-visible: +414 requests after load → +4. Big mobile win; networkidle settles 2.3s. No console errors.
060b63db0120c8c3e85c3883a18bad77a3705b90 · 2026-07-06 18:04:42 -0700 · Steve Abrams
Files touched
Diff
commit 060b63db0120c8c3e85c3883a18bad77a3705b90
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jul 6 18:04:42 2026 -0700
5x sweep: lazy-load grid thumbnails (IntersectionObserver) — grid used CSS background-images (can't use loading=lazy) so a big filter loaded 100s of images at once. Now bg applies only on-visible: +414 requests after load → +4. Big mobile win; networkidle settles 2.3s. No console errors.
---
public/index.html | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/public/index.html b/public/index.html
index 5ab8cf8..819f15b 100644
--- a/public/index.html
+++ b/public/index.html
@@ -584,7 +584,7 @@ function render(){
const el=document.createElement('div'); el.className='card'+(photographed?' done':'');
const badge=x.push_err?'<span class="badge b-err">PUSH ERR</span>':x.live?'<span class="badge b-live">● LIVE</span>':isNew?'<span class="badge b-new">✨ NEW</span>':photographed?'<span class="badge b-done">✓ PHOTO</span>':'<span class="badge b-need">NEEDS</span>';
const thumbUrl=x.photo||(isNew?'':x.image)||'';
- const thumb=thumbUrl?`style="background-image:url('${thumbUrl}')"`:'';
+ const thumb=thumbUrl?`data-bg="${thumbUrl}"`:''; // lazy: bg applied on-visible (see observer below)
const adjustable=photographed; // anything with a real photo can be re-opened in the editor
el.innerHTML=`
<div class="thumb ${adjustable?'tap':''}" ${thumb} title="${adjustable?'click to adjust':''}">${thumbUrl?'':'▦'}${badge}${x.product_id?`<button class="fav-btn${x.fav?' on':''}" title="favorite">${x.fav?'★':'☆'}</button>`:''}</div>
@@ -617,6 +617,15 @@ function render(){
const sk=el.querySelector('.skip'); if(sk) sk.addEventListener('click',()=>skip(x));
grid.appendChild(el);
}
+ lazyThumbs(); // only load thumbnails as they scroll into view (huge mobile win vs 100s of images at once)
+}
+// CSS background-images can't use loading="lazy" — apply each thumb's bg only when it nears the viewport.
+let _thumbObs=null;
+function lazyThumbs(){
+ if(_thumbObs) _thumbObs.disconnect();
+ if(!('IntersectionObserver' in window)){ grid.querySelectorAll('.thumb[data-bg]').forEach(t=>{ t.style.backgroundImage=`url('${t.getAttribute('data-bg')}')`; t.removeAttribute('data-bg'); }); return; }
+ _thumbObs=new IntersectionObserver((es,o)=>{ for(const e of es){ if(e.isIntersecting){ const t=e.target,u=t.getAttribute('data-bg'); if(u){ t.style.backgroundImage=`url('${u}')`; t.removeAttribute('data-bg'); } o.unobserve(t); } } },{rootMargin:'400px'});
+ grid.querySelectorAll('.thumb[data-bg]').forEach(t=>_thumbObs.observe(t));
}
function downscale(file,max=2000){return new Promise((res)=>{
const img=new Image(), url=URL.createObjectURL(file);
← 7754221 fix: print-sticker no longer hangs + go-live hardening
·
back to Dw Photo Capture
·
5x: report — desktop + mobile Chrome PASS (0 console errors) 5e67458 →