Beyond the Basics: Advanced Image Optimization for Developers
Six months ago, a senior developer on my team insisted our image optimization process was "already perfect." We were using WebP, implementing basic lazy loading, and serving responsive images—what more could we possibly need?
After an audit, we discovered several critical gaps: no AVIF support for compatible browsers, missing width/height attributes causing layout shifts, inefficient lazy loading implementation causing rendering delays, and image CDN configuration that ignored client hints. Addressing these technical shortcomings ultimately improved our Core Web Vitals scores by 27 points and cut image bandwidth by 43%.
This experience highlighted that truly effective image optimization requires deep technical knowledge that goes far beyond simply converting images to WebP. This post provides a comprehensive technical guide for developers who want to implement truly best-in-class image optimization.
Format Selection and Encoding Strategies
Let's start with the technical details of image formats and when to use each:
Vector vs. Raster Considerations
Different image types require fundamentally different approaches:
<!-- SVG for vector graphics -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L1 21h22L12 2z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
<!-- Optimized raster format for photographs -->
<img
src="https://demo.skymage/net/v1/example.com/photo.jpg?f=avif&q=75"
alt="Product photo"
width="800"
height="600"
onerror="this.onerror=null; this.src='https://demo.skymage/net/v1/example.com/photo.jpg?f=webp&q=75'">
Format Selection Logic
Implement smart content-type-based format selection:
// TypeScript example of format selection logic
interface FormatOptions {
supportsAVIF: boolean;
supportsWebP: boolean;
supportsJPEGXL: boolean;
hasPerfectTransparency: boolean;
isPhotographic: boolean;
hasAnimation: boolean;
hasText: boolean;
}
function selectOptimalFormat(options: FormatOptions): string {
const {
supportsAVIF,
supportsWebP,
supportsJPEGXL,
hasPerfectTransparency,
isPhotographic,
hasAnimation,
hasText
} = options;
// Vector graphics should use SVG
if (hasText && !isPhotographic) {
return 'svg';
}
// Animations require GIF, WebP or AVIF
if (hasAnimation) {
if (supportsAVIF) return 'avif';
if (supportsWebP) return 'webp';
return 'gif';
}
// Photographic content
if (isPhotographic) {
if (supportsJPEGXL) return 'jxl'; // Future-proofing
if (supportsAVIF) return 'avif';
if (supportsWebP) return 'webp';
return 'jpeg';
}
// Non-photographic with transparency
if (hasPerfectTransparency) {
if (supportsAVIF) return 'avif';
if (supportsWebP) return 'webp';
return 'png';
}
// Default fallback
if (supportsAVIF) return 'avif';
if (supportsWebP) return 'webp';
return 'jpeg';
}
Using the picture
Element for Format Fallbacks
Implement robust fallback chains:
<picture>
<!-- AVIF: Best compression, newest -->
<source
srcset="https://demo.skymage/net/v1/example.com/image.jpg?f=avif&q=65 1x,
https://demo.skymage/net/v1/example.com/image.jpg?f=avif&q=65&dpr=2 2x"
type="image/avif">
<!-- WebP: Good compression, better support -->
<source
srcset="https://demo.skymage/net/v1/example.com/image.jpg?f=webp&q=75 1x,
https://demo.skymage/net/v1/example.com/image.jpg?f=webp&q=75&dpr=2 2x"
type="image/webp">
<!-- JPEG: Universal fallback -->
<img
src="https://demo.skymage/net/v1/example.com/image.jpg?q=80"
srcset="https://demo.skymage/net/v1/example.com/image.jpg?q=80&dpr=2 2x"
alt="Description"
width="800"
height="600"
loading="lazy">
</picture>
Quality Selection Algorithms
Implement perceptual quality techniques:
// PHP example of content-aware quality selection
public function determineOptimalQuality(string $imagePath, string $format): int
{
// Load image
$image = $this->imageProcessor->load($imagePath);
// Extract image characteristics
$characteristics = $this->analyzeImageCharacteristics($image);
// Base quality varies by format
$baseQuality = match($format) {
'avif' => 65,
'webp' => 75,
'jpeg' => 80,
'png' => 90,
default => 75,
};
// Adjust based on content type
if ($characteristics['isPhotographic']) {
// Photos can often use lower quality with good results
$adjustment = -5;
} elseif ($characteristics['hasText']) {
// Text needs higher quality to remain crisp
$adjustment = +10;
} elseif ($characteristics['hasGradients']) {
// Gradients often show banding at low quality
$adjustment = +5;
} else {
$adjustment = 0;
}
// Adjust based on color complexity
$colorComplexity = $characteristics['colorComplexity']; // 0-100 scale
$complexityAdjustment = (int)($colorComplexity / 20) - 2; // -2 to +3 range
// Calculate final quality
$finalQuality = min(95, max(40, $baseQuality + $adjustment + $complexityAdjustment));
return $finalQuality;
}
Responsive Images Implementation
Optimal responsive images require attention to several technical details:
The Complete Responsive Image Syntax
Here's a complete example with all responsive attributes:
<picture>
<!-- Art direction: different crops for different viewports -->
<source
media="(max-width: 640px)"
srcset="https://demo.skymage/net/v1/example.com/product-mobile.jpg?f=avif 640w,
https://demo.skymage/net/v1/example.com/product-mobile.jpg?f=avif&dpr=2 1280w"
sizes="100vw"
type="image/avif">
<source
media="(max-width: 640px)"
srcset="https://demo.skymage/net/v1/example.com/product-mobile.jpg?f=webp 640w,
https://demo.skymage/net/v1/example.com/product-mobile.jpg?f=webp&dpr=2 1280w"
sizes="100vw"
type="image/webp">
<!-- Desktop image variants (resolution switching) -->
<source
srcset="https://demo.skymage/net/v1/example.com/product.jpg?f=avif&w=400 400w,
https://demo.skymage/net/v1/example.com/product.jpg?f=avif&w=800 800w,
https://demo.skymage/net/v1/example.com/product.jpg?f=avif&w=1200 1200w,
https://demo.skymage/net/v1/example.com/product.jpg?f=avif&w=1600 1600w"
sizes="(max-width: 1200px) 50vw, 33vw"
type="image/avif">
<source
srcset="https://demo.skymage/net/v1/example.com/product.jpg?f=webp&w=400 400w,
https://demo.skymage/net/v1/example.com/product.jpg?f=webp&w=800 800w,
https://demo.skymage/net/v1/example.com/product.jpg?f=webp&w=1200 1200w,
https://demo.skymage/net/v1/example.com/product.jpg?f=webp&w=1600 1600w"
sizes="(max-width: 1200px) 50vw, 33vw"
type="image/webp">
<!-- Fallback image -->
<img
src="https://demo.skymage/net/v1/example.com/product.jpg?w=800"
srcset="https://demo.skymage/net/v1/example.com/product.jpg?w=400 400w,
https://demo.skymage/net/v1/example.com/product.jpg?w=800 800w,
https://demo.skymage/net/v1/example.com/product.jpg?w=1200 1200w,
https://demo.skymage/net/v1/example.com/product.jpg?w=1600 1600w"
sizes="(max-width: 1200px) 50vw, 33vw"
alt="Product description"
width="800"
height="600"
loading="lazy"
decoding="async"
fetchpriority="auto">
</picture>
Automating the sizes
Attribute
The sizes
attribute is crucial but often misconfigured. Here's how to generate it programmatically:
// Function to calculate sizes attribute based on layout
function calculateSizesAttribute(elementSelector, breakpoints) {
const element = document.querySelector(elementSelector);
if (!element) return '100vw'; // Default fallback
// Get element's parent to determine constraints
const parent = element.parentElement;
const parentStyles = window.getComputedStyle(parent);
// Calculate sizes based on layout constraints
let sizesValue = '';
// Sort breakpoints in descending order
const sortedBreakpoints = [...breakpoints].sort((a, b) => b - a);
for (const breakpoint of sortedBreakpoints) {
// We need to test how the element behaves at each breakpoint
// This is a simplification - in production you'd need to use
// more sophisticated layout calculation
const relativeWidth = calculateRelativeWidth(element, breakpoint);
sizesValue += `(max-width: ${breakpoint}px) ${relativeWidth}vw, `;
}
// Add default size (for largest viewport)
const defaultRelativeWidth = calculateRelativeWidth(element);
sizesValue += `${defaultRelativeWidth}vw`;
return sizesValue;
}
// Helper function to estimate element's width relative to viewport
function calculateRelativeWidth(element, breakpoint = window.innerWidth) {
// This is a simplified approach - production code would
// need to handle more complex layouts
const parent = element.parentElement;
const parentStyles = window.getComputedStyle(parent);
// Check if parent has max-width constraint
let parentMaxWidth = Infinity;
if (parentStyles.maxWidth !== 'none') {
parentMaxWidth = parseInt(parentStyles.maxWidth);
}
// Determine if element is constrained by parent max-width
const effectiveViewportWidth = Math.min(breakpoint, parentMaxWidth);
// Calculate how much of the parent container the element occupies
const parentWidth = parent.offsetWidth;
const elementWidth = element.offsetWidth;
const elementRatio = elementWidth / parentWidth;
// Calculate parent container's width relative to viewport
const parentToViewportRatio = parentWidth / window.innerWidth;
// Element width as percentage of viewport
const elementToViewportRatio = elementRatio * parentToViewportRatio;
// Return as percentage value
return Math.round(elementToViewportRatio * 100);
}
// Usage
const imageSizes = calculateSizesAttribute('.product-image', [576, 768, 992, 1200]);
document.querySelector('.product-image').setAttribute('sizes', imageSizes);
Avoiding Common CLS Issues with Images
Prevent Cumulative Layout Shift with proper image handling:
<!-- Approach 1: Explicit dimensions -->
<img
src="https://demo.skymage/net/v1/example.com/product.jpg"
width="800"
height="600"
alt="Product">
<!-- Approach 2: Aspect ratio via CSS -->
<div style="aspect-ratio: 4/3;">
<img
src="https://demo.skymage/net/v1/example.com/product.jpg"
alt="Product"
style="width: 100%; height: 100%; object-fit: cover;">
</div>
<!-- Approach 3: Aspect ratio via padding technique -->
<div style="position: relative; padding-bottom: 75%;">
<img
src="https://demo.skymage/net/v1/example.com/product.jpg"
alt="Product"
style="position: absolute; width: 100%; height: 100%; object-fit: cover;">
</div>
Advanced Lazy Loading Techniques
Upgrade your lazy loading implementation:
Modern Native Lazy Loading with Proper Thresholds
<!-- Basic native lazy loading -->
<img
src="https://demo.skymage/net/v1/example.com/product.jpg"
loading="lazy"
alt="Product"
width="800"
height="600">
Pair with Intersection Observer for more control:
// Enhanced lazy loading with Intersection Observer
document.addEventListener('DOMContentLoaded', () => {
const lazyImages = document.querySelectorAll('img[loading="lazy"]');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
// If the image has a data-src attribute, use that for the source
if (img.dataset.src) {
img.src = img.dataset.src;
// Handle srcset as well if present
if (img.dataset.srcset) {
img.srcset = img.dataset.srcset;
}
// Clean up data attributes
delete img.dataset.src;
delete img.dataset.srcset;
}
// Upgrade image quality if needed
if (img.dataset.highQualitySrc) {
// Create a new image to preload the high-quality version
const highQualityImg = new Image();
highQualityImg.onload = () => {
img.src = highQualityImg.src;
if (img.dataset.highQualitySrcset) {
img.srcset = img.dataset.highQualitySrcset;
}
};
highQualityImg.src = img.dataset.highQualitySrc;
}
// Stop observing this image
observer.unobserve(img);
}
});
}, {
// Load when image is within 200px of viewport
rootMargin: '200px 0px',
threshold: 0.01
});
// Observe all lazy images
lazyImages.forEach(img => {
imageObserver.observe(img);
});
});
Priority Hints for Critical Images
Use the fetchpriority
attribute to prioritize important images:
<!-- Hero image: high priority -->
<img
src="https://demo.skymage/net/v1/example.com/hero.jpg"
alt="Hero"
fetchpriority="high"
width="1600"
height="900">
<!-- Non-critical image: low priority -->
<img
src="https://demo.skymage/net/v1/example.com/secondary.jpg"
alt="Secondary content"
fetchpriority="low"
loading="lazy"
width="800"
height="600">
Preloading Critical Images
Preload LCP images for faster rendering:
<!-- Preload hero image in the document head -->
<link
rel="preload"
as="image"
href="https://demo.skymage/net/v1/example.com/hero.jpg?w=1200&f=avif"
type="image/avif"
imagesrcset="https://demo.skymage/net/v1/example.com/hero.jpg?w=400&f=avif 400w,
https://demo.skymage/net/v1/example.com/hero.jpg?w=800&f=avif 800w,
https://demo.skymage/net/v1/example.com/hero.jpg?w=1200&f=avif 1200w"
imagesizes="100vw">
<!-- Also preload WebP version for browsers without AVIF support -->
<link
rel="preload"
as="image"
href="https://demo.skymage/net/v1/example.com/hero.jpg?w=1200&f=webp"
type="image/webp"
imagesrcset="https://demo.skymage/net/v1/example.com/hero.jpg?w=400&f=webp 400w,
https://demo.skymage/net/v1/example.com/hero.jpg?w=800&f=webp 800w,
https://demo.skymage/net/v1/example.com/hero.jpg?w=1200&f=webp 1200w"
imagesizes="100vw">
Client Hints Implementation
Use Client Hints to deliver optimized images:
Setting Up Client Hints
<!-- Enable client hints in the document head -->
<meta http-equiv="Accept-CH" content="DPR, Width, Viewport-Width, Device-Memory, RTT, Downlink, ECT">
<!-- Set lifetime for client hints -->
<meta http-equiv="Accept-CH-Lifetime" content="86400"> <!-- 24 hours -->
<!-- Delegate client hints to image CDN -->
<meta http-equiv="Critical-CH" content="DPR, Width, Viewport-Width">
<meta http-equiv="Delegate-CH" content="DPR https://demo.skymage, Width https://demo.skymage, Viewport-Width https://demo.skymage">
Using Client Hints with Images
<!-- Image utilizing client hints -->
<img
src="https://demo.skymage/net/v1/example.com/product.jpg?ch=true"
alt="Product"
width="800"
height="600"
sizes="50vw">
Server-Side Processing of Client Hints
// PHP example of handling Client Hints
public function processImageRequest(Request $request): Response
{
// Extract client hints from request headers
$clientHints = [
'dpr' => (float)($request->header('DPR') ?? 1.0),
'width' => (int)($request->header('Width') ?? 0),
'viewportWidth' => (int)($request->header('Viewport-Width') ?? 0),
'deviceMemory' => (float)($request->header('Device-Memory') ?? 4.0),
'rtt' => (int)($request->header('RTT') ?? 0),
'downlink' => (float)($request->header('Downlink') ?? 10.0),
'ect' => $request->header('ECT') ?? '4g',
];
// Extract requested image parameters
$imagePath = $request->input('path');
$requestedWidth = $request->input('w');
$requestedFormat = $request->input('f');
// Use client hints if explicit parameters aren't provided
$width = $requestedWidth ?: $this->calculateOptimalWidth($clientHints);
$format = $requestedFormat ?: $this->determineOptimalFormat($request->userAgent(), $clientHints);
$quality = $this->determineOptimalQuality($clientHints);
// Generate and serve optimized image
$optimizedImage = $this->imageService->optimize($imagePath, [
'width' => $width,
'format' => $format,
'quality' => $quality,
]);
return response($optimizedImage->getContents())
->header('Content-Type', $optimizedImage->getMimeType())
->header('Cache-Control', 'public, max-age=31536000')
->header('Vary', 'Accept, DPR, Width, Viewport-Width');
}
private function calculateOptimalWidth(array $clientHints): int
{
$dpr = $clientHints['dpr'];
$viewportWidth = $clientHints['viewportWidth'];
$requestedWidth = $clientHints['width'];
// If explicit Width hint is available, use that
if ($requestedWidth > 0) {
return $requestedWidth;
}
// Otherwise estimate based on viewport and DPR
if ($viewportWidth > 0) {
// Assume the image takes up about half the viewport
// This is a simplification - real logic would be more sophisticated
$estimatedWidth = $viewportWidth * 0.5 * $dpr;
// Round to nearest standard size
return $this->roundToStandardSize((int)$estimatedWidth);
}
// Fallback to a reasonable default
return 800;
}
private function roundToStandardSize(int $width): int
{
// Round to nearest standard breakpoint
$standardSizes = [320, 480, 640, 768, 1024, 1280, 1536, 1920, 2560];
foreach ($standardSizes as $standardSize) {
if ($width <= $standardSize) {
return $standardSize;
}
}
return end($standardSizes);
}
Performance Measurement and Monitoring
Implement proper measurement for image optimization:
Core Web Vitals Tracking for Images
Track and report on image-specific metrics:
// Register a performance observer for LCP
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Check if LCP element is an image
if (entry.element && entry.element.tagName === 'IMG') {
console.log('LCP is an image:', entry.element.src);
// Report image-specific LCP
analytics.track('image_lcp', {
url: entry.element.src,
lcp_value: entry.startTime,
element_id: entry.element.id || null,
element_class: entry.element.className || null,
viewport_width: window.innerWidth,
connection_type: navigator.connection ? navigator.connection.effectiveType : null
});
}
}
}).observe({ type: 'largest-contentful-paint', buffered: true });
// Track CLS caused by images
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Check if layout shift involves images
if (entry.sources) {
const involvesImages = entry.sources.some(source =>
source.node && source.node.tagName === 'IMG'
);
if (involvesImages) {
// Report image-related layout shift
analytics.track('image_layout_shift', {
cls_value: entry.value,
elements: entry.sources.map(source => ({
tag: source.node ? source.node.tagName : null,
id: source.node ? source.node.id : null,
src: source.node && source.node.tagName === 'IMG' ? source.node.src : null
}))
});
}
}
}
}).observe({ type: 'layout-shift', buffered: true });
Resource Timing Analysis for Images
Analyze image loading performance:
// Analyze image resource timing
function analyzeImagePerformance() {
// Get all resource entries
const entries = performance.getEntriesByType('resource');
// Filter for image resources
const imageEntries = entries.filter(entry =>
entry.initiatorType === 'img' ||
/\.(jpe?g|png|gif|webp|avif|svg)$/i.test(entry.name)
);
// Analyze each image
const imageStats = imageEntries.map(entry => {
// Find the corresponding DOM element
const selector = `img[src="${entry.name}"],
source[srcset*="${entry.name}"],
img[srcset*="${entry.name}"]`;
const element = document.querySelector(selector);
// Calculate metrics
const tcpTime = entry.connectEnd - entry.connectStart;
const requestTime = entry.responseStart - entry.requestStart;
const downloadTime = entry.responseEnd - entry.responseStart;
const totalTime = entry.responseEnd - entry.startTime;
return {
url: entry.name,
element: element ? {
id: element.id,
class: element.className,
width: element.width,
height: element.height,
loading: element.loading,
inViewport: isInViewport(element)
} : null,
size: entry.transferSize,
timing: {
dns: entry.domainLookupEnd - entry.domainLookupStart,
tcp: tcpTime,
request: requestTime,
download: downloadTime,
total: totalTime
},
cached: entry.transferSize === 0
};
});
// Group images by performance characteristics
const performanceGroups = {
fast: imageStats.filter(img => img.timing.total < 200),
medium: imageStats.filter(img => img.timing.total >= 200 && img.timing.total < 1000),
slow: imageStats.filter(img => img.timing.total >= 1000),
cached: imageStats.filter(img => img.cached)
};
// Identify problematic images
const problemImages = imageStats.filter(img => {
const hasLongDownload = img.timing.download > 500;
const isLarge = img.size > 200 * 1024; // 200KB
const isVisible = img.element && img.element.inViewport;
return (hasLongDownload || isLarge) && isVisible;
});
return {
totalImages: imageStats.length,
totalSize: imageStats.reduce((sum, img) => sum + img.size, 0),
averageLoadTime: imageStats.reduce((sum, img) => sum + img.timing.total, 0) / imageStats.length,
performanceGroups,
problemImages
};
}
// Helper function to check if element is in viewport
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= window.innerHeight &&
rect.right <= window.innerWidth
);
}
Build and Deployment Pipeline for Images
Implement an optimized image workflow:
Automated Build-Time Optimization
Here's a webpack configuration for image optimization:
// webpack.config.js
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
module.exports = {
// ... other webpack config
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // Inline images < 10kb
}
}
}
]
},
optimization: {
minimizer: [
// ... other minimizers
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminMinify,
options: {
plugins: [
['gifsicle', { interlaced: true, optimizationLevel: 3 }],
['jpegtran', { progressive: true }],
['optipng', { optimizationLevel: 5 }],
[
'svgo',
{
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
addAttributesToSVGElement: {
params: {
attributes: [
{ xmlns: 'http://www.w3.org/2000/svg' }
]
}
}
}
}
}
]
}
]
]
}
},
generator: [
{
preset: 'webp',
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: ['imagemin-webp']
}
},
{
preset: 'avif',
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: ['imagemin-avif']
}
}
]
})
]
},
// Generate manifest of optimized images
plugins: [
// ... other plugins
new (class {
apply(compiler) {
compiler.hooks.emit.tapAsync('ImageManifestPlugin', (compilation, callback) => {
const manifest = {};
// Collect all image assets
for (const filename in compilation.assets) {
if (/\.(jpe?g|png|gif|webp|avif|svg)$/i.test(filename)) {
const asset = compilation.assets[filename];
manifest[filename] = {
size: asset.size(),
originalName: filename.replace(/\.(webp|avif)$/, '')
};
}
}
// Add manifest to compilation
compilation.assets['image-manifest.json'] = {
source: () => JSON.stringify(manifest, null, 2),
size: () => JSON.stringify(manifest, null, 2).length
};
callback();
});
}
})()
]
};
Git Hooks for Image Optimization
Use Git hooks to ensure all committed images are optimized:
#!/bin/bash
# .git/hooks/pre-commit
# Get all staged image files
staged_images=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(jpg|jpeg|png|gif|svg)$')
if [ -n "$staged_images" ]; then
echo "Optimizing staged images..."
# Create a temporary directory for optimized images
temp_dir=$(mktemp -d)
for image in $staged_images; do
# Skip already optimized images
if grep -q "$image" .optimized-images 2>/dev/null; then
echo "Skipping already optimized image: $image"
continue
fi
echo "Optimizing: $image"
# Optimize based on file extension
if [[ $image =~ \.(jpg|jpeg)$ ]]; then
# Optimize JPEG
jpegoptim --strip-all --max=85 "$image"
elif [[ $image =~ \.png$ ]]; then
# Optimize PNG
optipng -o5 "$image"
elif [[ $image =~ \.gif$ ]]; then
# Optimize GIF
gifsicle -O3 -o "${temp_dir}/$(basename "$image")" "$image"
mv "${temp_dir}/$(basename "$image")" "$image"
elif [[ $image =~ \.svg$ ]]; then
# Optimize SVG
svgo --multipass "$image"
fi
# Add to optimized images list
echo "$image" >> .optimized-images
# Re-add the optimized image to staging
git add "$image"
done
# Clean up
rm -rf "$temp_dir"
echo "Image optimization complete"
fi
# Continue with commit
exit 0
Implementing with Skymage
Let's look at how to implement these best practices using Skymage:
Direct Integration with HTML
<!-- Basic implementation -->
<img
src="https://demo.skymage/net/v1/example.com/image.jpg?auto=format,compress&q=auto"
alt="Description"
width="800"
height="600"
loading="lazy">
<!-- Advanced implementation with all optimizations -->
<picture>
<source
type="image/avif"
srcset="https://demo.skymage/net/v1/example.com/image.jpg?f=avif&w=400&q=65 400w,
https://demo.skymage/net/v1/example.com/image.jpg?f=avif&w=800&q=65 800w,
https://demo.skymage/net/v1/example.com/image.jpg?f=avif&w=1200&q=65 1200w"
sizes="(max-width: 768px) 100vw, 50vw">
<source
type="image/webp"
srcset="https://demo.skymage/net/v1/example.com/image.jpg?f=webp&w=400&q=75 400w,
https://demo.skymage/net/v1/example.com/image.jpg?f=webp&w=800&q=75 800w,
https://demo.skymage/net/v1/example.com/image.jpg?f=webp&w=1200&q=75 1200w"
sizes="(max-width: 768px) 100vw, 50vw">
<img
src="https://demo.skymage/net/v1/example.com/image.jpg?w=800&q=80"
srcset="https://demo.skymage/net/v1/example.com/image.jpg?w=400&q=80 400w,
https://demo.skymage/net/v1/example.com/image.jpg?w=800&q=80 800w,
https://demo.skymage/net/v1/example.com/image.jpg?w=1200&q=80 1200w"
sizes="(max-width: 768px) 100vw, 50vw"
alt="Description"
width="800"
height="600"
loading="lazy">
</picture>
Using the JavaScript SDK
// Skymage JavaScript SDK integration
import { SkymageOptimizer } from '@skymage/js';
// Initialize with your account details
const skymage = new SkymageOptimizer({
domain: 'demo.skymage',
detectWebpSupport: true,
detectAvifSupport: true,
detectViewportWidth: true,
detectDPR: true,
useSrcset: true
});
// Basic URL transformation
const optimizedUrl = skymage.getOptimizedUrl('https://example.com/image.jpg', {
width: 800,
quality: 'auto',
format: 'auto'
});
// Generate complete picture element
function generateOptimizedPicture(originalUrl, alt, sizes, options = {}) {
const {
width = 800,
height = 600,
loading = 'lazy',
widths = [400, 800, 1200, 1600],
formats = ['avif', 'webp', 'original']
} = options;
const picture = document.createElement('picture');
// Add source elements for each format
formats.forEach(format => {
if (format === 'original') return; // Skip original format for source elements
const source = document.createElement('source');
source.type = `image/${format}`;
// Generate srcset with multiple widths
const srcset = widths.map(w => {
const url = skymage.getOptimizedUrl(originalUrl, {
width: w,
format
});
return `${url} ${w}w`;
}).join(', ');
source.srcset = srcset;
source.sizes = sizes;
picture.appendChild(source);
});
// Create img element (fallback)
const img = document.createElement('img');
img.src = skymage.getOptimizedUrl(originalUrl, { width });
// Generate srcset for fallback image
const imgSrcset = widths.map(w => {
const url = skymage.getOptimizedUrl(originalUrl, { width: w });
return `${url} ${w}w`;
}).join(', ');
img.srcset = imgSrcset;
img.sizes = sizes;
img.alt = alt;
img.width = width;
img.height = height;
img.loading = loading;
picture.appendChild(img);
return picture;
}
// Usage
const productPicture = generateOptimizedPicture(
'https://example.com/product.jpg',
'Product description',
'(max-width: 768px) 100vw, 50vw',
{
width: 800,
height: 600,
loading: 'lazy',
widths: [400, 800, 1200]
}
);
document.querySelector('.product-container').appendChild(productPicture);
Server-Side Integration
// PHP server-side integration
class SkymageImageOptimizer
{
private string $domain = 'demo.skymage';
public function getOptimizedUrl(string $originalUrl, array $options = []): string
{
// Extract domain and path from original URL
$urlParts = parse_url($originalUrl);
$path = $urlParts['path'] ?? '';
$host = $urlParts['host'] ?? '';
if (empty($host)) {
throw new InvalidArgumentException('Invalid URL provided');
}
// Build base URL
$optimizedUrl = "https://{$this->domain}/net/v1/{$host}{$path}";
// Add query parameters
$queryParams = [];
// Process options
if (!empty($options['width'])) {
$queryParams['w'] = (int)$options['width'];
}
if (!empty($options['height'])) {
$queryParams['h'] = (int)$options['height'];
}
if (!empty($options['format'])) {
$queryParams['f'] = $options['format'];
}
if (!empty($options['quality'])) {
$queryParams['q'] = $options['quality'];
}
if (!empty($options['crop'])) {
$queryParams['fit'] = $options['crop'];
}
if (!empty($options['blur'])) {
$queryParams['blur'] = (int)$options['blur'];
}
if (!empty($options['dpr'])) {
$queryParams['dpr'] = (float)$options['dpr'];
}
// Add client hints support
if (!empty($options['clientHints']) && $options['clientHints'] === true) {
$queryParams['ch'] = 'true';
}
// Add automatic optimization
if (empty($options['format']) && empty($options['quality'])) {
$queryParams['auto'] = 'format,quality';
}
// Combine into URL
if (!empty($queryParams)) {
$queryString = http_build_query($queryParams);
$optimizedUrl .= "?{$queryString}";
}
return $optimizedUrl;
}
public function generatePictureElement(
string $originalUrl,
string $alt,
string $sizes,
array $options = []
): string {
// Default options
$options = array_merge([
'width' => 800,
'height' => 600,
'loading' => 'lazy',
'widths' => [400, 800, 1200],
'formats' => ['avif', 'webp', 'original'],
'quality' => [
'avif' => 65,
'webp' => 75,
'original' => 80
]
], $options);
// Start building picture element
$html = '<picture>';
// Add source elements for each format
foreach ($options['formats'] as $format) {
if ($format === 'original') continue;
$quality = $options['quality'][$format] ?? 'auto';
$html .= '<source type="image/' . htmlspecialchars($format) . '" ';
// Generate srcset
$srcset = [];
foreach ($options['widths'] as $width) {
$url = $this->getOptimizedUrl($originalUrl, [
'width' => $width,
'format' => $format,
'quality' => $quality
]);
$srcset[] = htmlspecialchars($url) . ' ' . $width . 'w';
}
$html .= 'srcset="' . implode(', ', $srcset) . '" ';
$html .= 'sizes="' . htmlspecialchars($sizes) . '">';
}
// Add fallback img element
$quality = $options['quality']['original'] ?? 'auto';
$fallbackUrl = $this->getOptimizedUrl($originalUrl, [
'width' => $options['width'],
'quality' => $quality
]);
$html .= '<img ';
$html .= 'src="' . htmlspecialchars($fallbackUrl) . '" ';
// Generate srcset for fallback
$srcset = [];
foreach ($options['widths'] as $width) {
$url = $this->getOptimizedUrl($originalUrl, [
'width' => $width,
'quality' => $quality
]);
$srcset[] = htmlspecialchars($url) . ' ' . $width . 'w';
}
$html .= 'srcset="' . implode(', ', $srcset) . '" ';
$html .= 'sizes="' . htmlspecialchars($sizes) . '" ';
$html .= 'alt="' . htmlspecialchars($alt) . '" ';
$html .= 'width="' . (int)$options['width'] . '" ';
$html .= 'height="' . (int)$options['height'] . '" ';
$html .= 'loading="' . htmlspecialchars($options['loading']) . '">';
$html .= '</picture>';
return $html;
}
}
// Usage in a PHP application
$imageOptimizer = new SkymageImageOptimizer();
// Simple usage
$optimizedUrl = $imageOptimizer->getOptimizedUrl(
'https://example.com/product.jpg',
['width' => 800, 'auto' => 'format,quality']
);
// Generate complete picture element
$pictureHtml = $imageOptimizer->generatePictureElement(
'https://example.com/product.jpg',
'Product description',
'(max-width: 768px) 100vw, 50vw',
[
'width' => 800,
'height' => 600,
'loading' => 'lazy',
'widths' => [400, 800, 1200]
]
);
echo $pictureHtml;
Conclusion
Implementing comprehensive image optimization requires going beyond the basics. By applying the advanced techniques outlined in this post—format selection based on content type, complete responsive image syntax, client hints integration, sophisticated lazy loading, and proper performance measurement—you can achieve significantly better results than standard approaches.
Remember that image optimization is not a one-time task but an ongoing process that requires continued monitoring and refinement. The technical approaches outlined here should be integrated into your development workflow to ensure consistent implementation across your application.
Skymage provides all the tools needed to implement these advanced techniques with minimal development effort, allowing you to focus on your application while still delivering best-in-class image performance.
Ready to implement advanced image optimization techniques in your application? Contact Skymage to discuss the best approach for your specific technical requirements.