[object Object]

← 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 →