SmartSize uses a comprehensive image optimization strategy inside the popup to reduce bandwidth, improve Core Web Vitals, and maintain a responsive experience across devices.
This reference describes the optimization strategies, components, and utilities that handle product images in the quiz and size chart popups.
Optimization strategies
Lazy loading
All images inside the popup use the loading="lazy" attribute. Images below the fold or inside collapsed steps are deferred until the user scrolls or navigates to them.
Benefits:
Reduces initial page load time
Saves bandwidth for users who do not scroll to images
Improves Core Web Vitals (LCP, CLS)
Applies to:
Multiple choice option images
Bra size step images
Size chart images
Product thumbnails
Explicit image dimensions
Every image has explicit width and height attributes. The browser reserves space before the image loads, preventing layout shift.
Benefits:
Prevents layout shifts (CLS improvement)
Allows browser to reserve space before image loads
Improves rendering performance
Example:
<img src="image.webp" alt="Size guide illustration" width="80" height="80" loading="lazy" />
Image preloading
Critical images are preloaded using <link rel="preload"> when the popup opens or when a step becomes active. Non-critical images remain lazy-loaded.
Preloaded images:
Button icons
Product images on the winner screen
Quiz step images when the step is active
Bra size step images
Benefits:
Critical images load faster
Reduces perceived loading time
Improves user experience for key interactions
Error handling
Every image has an onError handler. If an image fails to load, it is hidden gracefully rather than showing a broken placeholder.
Benefits:
Graceful degradation when images fail to load
Prevents broken image placeholders
Better user experience
Modern image formats
SmartSize serves images in WebP format where supported. The image utilities include detection logic for AVIF support and will upgrade when the browser supports it.
Benefits:
Smaller file sizes (25–35% smaller than JPEG)
Better compression
Faster loading times
Components and utilities
OptimizedImage component
A reusable Preact component that wraps all optimization best practices:
<OptimizedImage
src="image.webp"
alt="Size guide illustration"
width={80}
height={80}
preload={true}
fallbackSrc="fallback.jpg"
onLoad={() => console.log('Image loaded')}
onError={() => console.log('Image failed')}
/>
Features:
Automatic lazy loading (
loading="lazy"by default)Loading state management
Error handling with fallbacks
Optional preloading
Smooth opacity transitions
Image optimization utilities
Location: src/utils/imageOptimization.ts
optimizeImageUrl(url, options)
Adds Shopify CDN optimization parameters to an image URL.
const optimizedUrl = optimizeImageUrl(originalUrl, {
format: 'webp',
quality: 85,
width: 400
});
generateSrcSet(baseUrl, widths, options)
Creates responsive image srcset attributes for different viewport sizes.
const srcset = generateSrcSet(baseUrl, [320, 640, 960], {
format: 'webp',
quality: 85
});
// Returns: "url_320.webp 320w, url_640.webp 640w, url_960.webp 960w"
preloadImage(url) / preloadImages(urls)
Preloads individual or multiple images programmatically.
await preloadImages(['image1.webp', 'image2.webp']);
getSupportedFormats()
Detects browser support for modern image formats.
const formats = getSupportedFormats();
// { webp: true, avif: false }
measureImageLoadTime(url)
Measures image load performance for monitoring.
const loadTime = await measureImageLoadTime(imageUrl);
console.log(`Image loaded in ${loadTime}ms`);
Performance impact
Before optimization
❌ No lazy loading
❌ Missing image dimensions
❌ No error handling
❌ Limited preloading
❌ No format optimization
After optimization
✅ Lazy loading on all images
✅ Explicit dimensions preventing layout shifts
✅ Comprehensive error handling
✅ Strategic preloading of critical images
✅ WebP format usage
✅ Performance monitoring utilities
✅ Reusable optimized components
Expected performance gains
Metric | Improvement |
LCP (Largest Contentful Paint) | 20–30% faster |
CLS (Cumulative Layout Shift) | 50–70% reduction |
Bandwidth usage | 25–35% reduction (WebP vs JPEG) |
Perceived performance | Significant improvement |
Implementation by component
MultipleChoiceStep
Preloads all step images when the component mounts
Lazy loading for individual option images
Error handling with graceful degradation
Explicit dimensions for all images
BraSizeStep
Preloads bra size step images
Lazy loading for method selection images
Error handling for all images
Optimized image dimensions
Main app component
Preloads critical images (button icon, product image)
Lazy loading for modal images
Error handling for all images
Optimized loading strategy
Future enhancements
Enhancement | Description |
AVIF format support | Automatic detection and usage when supported. Further 20–30% size reduction over WebP. |
Responsive | Serve different image sizes based on device pixel density and viewport. |
Progressive loading | Show low-quality placeholders first, then sharpen. |
Server-side compression | Automatic quality adjustment based on content type. |
Edge caching | Leverage Shopify CDN features for faster global delivery. |
Best practices
Always use explicit dimensions for images.
Implement lazy loading for non-critical images.
Preload critical images that are above the fold or immediately visible.
Use modern formats (WebP, AVIF) when possible.
Handle errors gracefully with fallbacks.
Monitor performance and optimize based on metrics.
Use responsive images for different screen sizes.
Optimize image quality based on use case.
Testing
Manual testing
Check image loading in different network conditions (Fast 3G, Slow 3G)
Verify lazy loading behavior in browser DevTools Network panel
Test error handling by blocking image URLs
Monitor layout shifts using DevTools Performance panel
Automated testing
Lighthouse performance audits
Core Web Vitals monitoring
Image optimization validation
Related articles
CSS customization reference — Styling the popup and buttons
Styling resilience and conflict prevention — Preventing theme CSS conflicts
