074
LVL 03 — MID DEVELOPERSESSION 074DAY 74

IMAGE OPTIMIZATION

🎫 PIXELCRAFT-061
Performance | 🟡 Medium | Priority: 🟠 High

The gallery loads full-resolution images for thumbnails. Page weight is 40MB. Mobile users are leaving. Optimize: WebP thumbnails, responsive images, lazy loading.
CONCEPTS.UNLOCKED
🖼️
Modern Image Formats
WebP: 25-35% smaller than JPEG. AVIF: 50% smaller. Both support transparency. Browser support is now universal for WebP. AVIF is catching up fast.
📐
Responsive Images (srcset)
Serve the right size for the device. srcset lets the browser choose: 400w for mobile, 800w for tablet, 1200w for desktop. No wasted bandwidth.
😴
Lazy Loading
Don't load what the user can't see. loading="lazy" defers offscreen images. Intersection Observer gives you programmatic control. Page loads fast, images appear as you scroll.
🔍
Thumbnail Optimization
Generate multiple sizes server-side. Upload a 4000px image → generate 200px thumbnail, 800px preview, original. Serve the smallest version that looks good at display size.
📊
Image Compression
Quality vs file size tradeoff. JPEG quality 80 is visually identical to 100 at half the size. Canvas.toBlob() with quality parameter for client-side compression.
🎯
Core Web Vitals
LCP (Largest Contentful Paint). Images are usually the largest element. Optimized images directly improve your LCP score — the metric Google uses for ranking.
HANDS-ON.TASKS
01
Responsive Images with srcset
<img src="photo-800.webp" srcset=" photo-400.webp 400w, photo-800.webp 800w, photo-1200.webp 1200w" sizes=" (max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px" loading="lazy" alt="User photo" /> <!-- With format fallback --> <picture> <source srcset="photo-800.avif" type="image/avif" /> <source srcset="photo-800.webp" type="image/webp" /> <img src="photo-800.jpg" alt="User photo" /> </picture>
02
Lazy Loading with Intersection Observer
function LazyImage({ src, alt }) { const imgRef = useRef(null); const [loaded, setLoaded] = useState(false); useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { imgRef.current.src = src; observer.unobserve( imgRef.current); } }, { rootMargin: '200px' } // Start loading 200px before visible ); observer.observe(imgRef.current); return () => observer.disconnect(); }, [src]); return ( <img ref={imgRef} alt={alt} onLoad={() => setLoaded(true)} className={loaded ? 'fade-in' : 'placeholder'} /> ); }
03
Client-Side WebP Export
function exportAsWebP(canvas, quality = 0.8) { return new Promise((resolve) => { canvas.toBlob( (blob) => { const url = URL.createObjectURL(blob); resolve({ blob, url }); }, 'image/webp', quality ); }); } // Compare sizes const jpeg = await exportAs( canvas, 'image/jpeg', 0.9); const webp = await exportAsWebP( canvas, 0.8); console.log( `JPEG: ${(jpeg.blob.size / 1024) .toFixed(0)}KB`); console.log( `WebP: ${(webp.blob.size / 1024) .toFixed(0)}KB`);
04
Measure the Improvement
MetricBeforeAfter
Gallery page weight40MB3.2MB
Initial images loaded50 (all)8 (visible)
Thumbnail size2MB each40KB each
LCP8.2s1.4s
05
Close the Ticket
git switch -c feature/PIXELCRAFT-061-image-optimization git add src/ server/ git commit -m "Add WebP, srcset, lazy loading (PIXELCRAFT-061)" git push origin feature/PIXELCRAFT-061-image-optimization # PR → Review → Merge → Close ticket ✅
CS.DEEP-DIVE

Image compression is applied mathematics.

Every image format uses a different strategy to throw away information humans won't notice.

// How image compression works:

JPEG (1992)
  DCT (Discrete Cosine Transform)
  Removes high-frequency detail
  Lossy. No transparency.

PNG (1996)
  DEFLATE compression (like gzip)
  Lossless. Supports transparency.
  Large files for photos.

WebP (2010, Google)
  VP8 video codec for still images
  25-35% smaller than JPEG

AVIF (2019, Alliance for Open Media)
  AV1 video codec for still images
  50% smaller than JPEG

// The pattern: video codecs are better
// at compression → adapt them for images.
"Performance Lab"
[A]Build a server-side image pipeline: on upload, generate 3 sizes (thumbnail 200px, preview 800px, original) in both WebP and JPEG using Sharp (npm install sharp). Store all variants.
[B]Add blur-up loading: show a tiny 20px blurred placeholder → fade in the full image when loaded. Instagram and Medium use this technique for perceived performance.
[C]Audit with Lighthouse: run a performance audit on the gallery page before and after optimization. Screenshot the LCP, CLS, and FID scores. Target all green (90+).
REF.MATERIAL
ARTICLE
Google Chrome Team
Comprehensive image optimization guide: formats, compression, responsive images, lazy loading, and CDN delivery. The modern reference.
IMAGESOFFICIALESSENTIAL
VIDEO
Fireship
Quick overview of modern image formats, srcset, lazy loading, and Sharp for server-side processing. Practical and fast-paced.
IMAGESQUICK
ARTICLE
MDN Web Docs
srcset, sizes, and the picture element explained. How the browser chooses the right image for the device.
SRCSETMDNOFFICIAL
ARTICLE
Lovell Fuller
The fastest Node.js image processing library. Resize, convert, compress images server-side. Powers most Node.js image pipelines.
SHARPNODE.JS
ARTICLE
Google Chrome Team
LCP, FID, CLS explained. The performance metrics that affect SEO rankings and user experience. Measure what matters.
PERFORMANCEMETRICS
// LEAVE EXCITED BECAUSE
Gallery went from 40MB to 3.2MB. LCP dropped from 8s to 1.4s. Images load as you scroll, in the perfect size for your screen. Performance is a feature — and now yours is excellent.