Strategies for Optimizing Images for Better Web Performance
Strategies for Optimizing Images for Better Web Performance
Images are often the largest files on a web page and can significantly impact load times and overall performance. Here are some strategies to optimize images for better web performance:
Why Images Slow Down Websites
- File Size Overhead - Large JPEGs or PNGs can weigh several MBs each.
- Wrong Formats - Using PNGs where WebP or AVIF would have cut the size in half.
- No Responsive Variants - Loading a 2000px image on a 400px mobile screen.
- Eager Loading - Forcing all images to load at once, even those below the fold.
Each of these adds unnecessary weight, slows down rendering, and creates a poor user experience.
Measuring Image Performance Impact
You can use tools like Lighthouse, WebPageTest, or GTmetrix to analyze your website's performance and identify image-related issues. Look for metrics like Largest Contentful Paint (LCP) and Total Blocking Time (TBT) to see how images affect load times.
Image Optimization Strategies
(summary of techniques, details below)
- Modern Formats: Use modern image formats like WebP or AVIF for better compression and quality.
- Responsive Images: Serve different image sizes based on the user's device using `src
- Lazy Loading: Implement lazy loading for offscreen images to reduce initial load time.
- Compression: Use tools like ImageOptim or TinyPNG to compress images without losing quality.
- CDN: Serve images from a Content Delivery Network (CDN) to reduce latency.
- Image Dimensions: Always specify width and height attributes to prevent layout shifts.
- SVG Optimization: Convert SVGs to inline SVGs and optimize them using tools like SVGO.
- Use CSS Sprites: Combine multiple images into a single sprite sheet to reduce HTTP requests.
- Cache Control: Set appropriate cache headers to leverage browser caching for images.
- Preload Key Images: Use the
preloadattribute for critical images to ensure they load quickly.
1. Switching to Modern Formats (WebP / AVIF)
Use modern formats like WebP or AVIF for better compression and quality. Reserve JPEG and PNG for legacy support.
WebP offers 25-35% smaller sizes than JPEG/PNG without noticeable quality loss. AVIF compresses even better, though with slower encoding.
Example (Next.js next/image automatically serves WebP/AVIF when supported):
import Image from "next/image";
export default function Hero() {
return (
<Image
src="/assets/images/balloons.jpg"
alt="Colorful Balloons"
width={1200}
height={600}
priority
/>
);
}
2. Using Responsive Images and the dimensions i rendered (srcset)
Use the srcset attribute to serve different image sizes based on the user's device.
Instead of serving one giant image, you can generated multiple sizes and let the browser choose the best one.
<img
src="balloons-800.webp"
srcset="balloons-400.webp 400w, balloons-800.webp 800w, balloons-1200.webp 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
alt="Colorful Balloons"
/>
This prevents a mobile device from wasting bandwidth on desktop-sized images.
⸻
3. Converting small Images to Base64
This has been the best hack for fixing the LCP which I highly recommend, convert the images to the required dimensions in webp format, and then converted this images to Base64 string, which I injected in the img code directly.
{/*
Before
<Image
src={"/images/tree.png"} // instead use base64
alt={`Image is a tree`}
width={150}
priority
id="tree-image"
height={150}
aria-label="Image is a tree"
/> */}
<Image
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAYAAAA+s"
alt={`Image is a tree`}
width={150}
id="tree-image"
height={150}
aria-label="Image is a tree"
/>
You can use a tool like Image to Base64 to convert the image to base64 and then copy the string it generates and paste in the src of the Image element.
3. Lazy Loading Images Below the Fold
Lazy loading defers non-critical images until they're about to enter the viewport.
<img src="gallery-1.webp" loading="lazy" alt="Gallery item" />
In React/Next.js, next/image has loading="lazy" by default.
import Image from 'next/image';
<Image
loading="lazy" // add this
fetchPriority="low" // add this
src={optimizedAvatarUrl.toString()}
alt={avatarAlt}
width={width}
height={height}
className="rounded-full object-cover"
priority
/>
4. Compressing Aggressively
- TinyPNG / TinyJPG for quick manual compression.
- Sharp for automated build-time optimization.
- Cloudflare Images or Imgix for on-the-fly CDN-based compression.
5. Serving via a CDN
Instead of pulling images directly from my server, I cached and delivered them via a CDN. This reduced latency and improved global performance.
Image Optimization Tools
- Squoosh - Google's free browser-based converter.
- Sharp - Node.js image processing library for automation.
- iLoveImg - Free online image compressor and converter.
- Image to Base64 - Free online tool to convert images to Base64 strings.
- Cloudflare Images - CDN with built-in image optimization.
- Imgix - Real-time image processing and CDN.
- ImageOptim - Mac app for lossless image compression.
- TinyPNG / TinyJPG - Online tool for compressing PNG and JPEG images.
- SVGO - Node.js-based tool for optimizing SVG files.
