HDR Images on the Web: Complete Implementation Guide
Learn how to serve HDR images on the web. Covers HDR formats, display detection, tone mapping, and practical implementation for modern browsers and devices.
HDR (High Dynamic Range) displays are now mainstream in phones, laptops, and monitors. Billions of screens shipped in the last few years can render brighter highlights, deeper shadows, and more vivid colors than traditional SDR panels ever could. This guide covers how to serve HDR images on the web, from format selection and capture techniques to display detection, tone mapping, and real-world testing.
What is HDR?
HDR stands for High Dynamic Range. In the context of imaging, dynamic range refers to the span between the darkest shadow and the brightest highlight that can be captured or displayed. A traditional SDR (Standard Dynamic Range) image or screen can reproduce roughly six stops of light, which is enough for everyday photos but falls short of what the human eye can perceive in high-contrast scenes like sunsets, neon-lit streets, or studio-lit product shots.
HDR images push that range to ten or more stops. This means a photo of a sunset can show both the glowing disc of the sun at realistic brightness and the shadowed foreground without either being clipped. On an HDR display, specular highlights in jewelry or the glare on a car hood can genuinely appear to “pop” off the screen because the panel drives those pixels to several hundred — or even over a thousand — nits of luminance, far beyond the roughly 100-nit ceiling of SDR.
Beyond brightness, HDR images also carry wider color gamut data. Instead of being limited to the sRGB color space that has defined web imagery since the 1990s, HDR content typically uses Display P3 or Rec. 2020, which can represent deep reds, vivid greens, and saturated blues that sRGB simply cannot encode. Combined with 10-bit or higher bit depth (versus the 8 bits per channel in conventional JPEG), this produces smoother gradients and eliminates the banding artifacts visible in skies and soft shadows.
For web developers, the practical upshot is that HDR images look dramatically better on capable hardware — and the share of capable hardware is growing fast. But the web still has to serve billions of SDR screens, which makes a thoughtful implementation strategy essential.
Understanding HDR on the Web
What Makes an Image HDR?
An image qualifies as HDR when it exceeds the limits of standard dynamic range in one or more dimensions: luminance range, color gamut, or bit depth. Most true HDR images combine all three.
| Property | SDR | HDR |
|---|---|---|
| Dynamic range | ~6 stops | 10+ stops |
| Peak brightness | 100 nits | 400-1000+ nits |
| Color space | sRGB | Display P3 / Rec. 2020 |
| Bit depth | 8-bit | 10-bit or higher |
| Typical file formats | JPEG, PNG, WebP | AVIF, JPEG XL, HDR HEIF |
| Transfer function | sRGB gamma (~2.2) | PQ (ST 2084) or HLG |
The transfer function row is worth highlighting. SDR content uses a simple gamma curve that maxes out at a reference white of roughly 100 nits. HDR content uses Perceptual Quantizer (PQ) or Hybrid Log-Gamma (HLG) curves that can encode luminance values up to 10,000 nits, giving the display freedom to map those values to its actual peak brightness.
HDR Display Adoption
As of early 2026, HDR-capable screens are the majority on mobile and growing steadily on desktop.
| Device Category | HDR Support | Peak Brightness | Color Gamut |
|---|---|---|---|
| iPhone 12 and later | HDR, Display P3 | 1200 nits (HDR) | P3 |
| iPhone 15 Pro / 16 Pro | HDR, Display P3 | 1600-2000 nits (HDR) | P3 |
| MacBook Pro (M-series) | HDR, XDR Display | 1600 nits sustained | P3 |
| MacBook Air (M2+) | HDR, Display P3 | 500 nits | P3 |
| iPad Pro (M-series) | HDR, XDR Display | 1600 nits | P3 |
| iPad Air (M-series) | HDR, Display P3 | 600 nits | P3 |
| Samsung Galaxy S24/S25 | HDR10+ | 2600 nits (peak) | P3 |
| Google Pixel 9 series | HDR | 1800-2700 nits (peak) | P3 |
| High-end PC monitors | HDR10 / HDR400-1000 | 400-1000+ nits | P3 or wider |
| Most budget laptops | SDR only | 250-350 nits | sRGB |
| Most external monitors | SDR only | 250-350 nits | sRGB |
The key takeaway: mobile users are far more likely to have an HDR display than desktop users. This aligns well with a progressive enhancement strategy where you serve HDR assets to devices that can benefit and fall back gracefully everywhere else.
HDR Photography: Capture Techniques
Before you can serve HDR images on the web, someone has to create them. HDR photography encompasses several approaches, each with different trade-offs.
Exposure Bracketing
The classic HDR photography technique involves shooting multiple exposures of the same scene — typically three to seven frames at different shutter speeds, each separated by one or two stops. The underexposed frames preserve highlight detail (clouds, light sources), while the overexposed frames capture shadow detail (interiors, dark foliage). Specialized software then merges these brackets into a single HDR image.
Popular tools for merging brackets include Adobe Lightroom, Photomatix, Aurora HDR, and the open-source Luminance HDR. The merge process aligns the frames (important if shooting handheld), removes ghosting artifacts from moving objects, and produces a 32-bit floating-point image that contains the full dynamic range of the scene.
Tone Mapping vs. True HDR Output
Historically, HDR photography was synonymous with tone mapping — compressing the merged 32-bit image back down into an 8-bit SDR file for display on conventional screens. This produced the “HDR look” of hyper-detailed, sometimes surreal images. While tone-mapped HDR images can be striking, they are still SDR files.
True HDR output preserves the extended dynamic range and encodes it with a PQ or HLG transfer function so that an HDR display can render highlights above the SDR white point. This is the kind of HDR image this guide focuses on.
Single-Shot HDR on Smartphones
Modern smartphones use computational HDR photography to capture extended dynamic range in a single shutter press. Apple’s Smart HDR (iPhone), Google’s HDR+ (Pixel), and Samsung’s multi-frame HDR all capture a rapid burst of frames at varying exposures and fuse them in the image signal processor. The resulting photos are often saved with HDR gain maps — an embedded secondary image that tells HDR displays how to boost highlights beyond the SDR baseline.
Apple’s gain map approach (used in HEIF and JPEG on iPhone 12+) is particularly relevant for the web because Safari and macOS can interpret gain maps to display the HDR rendition on capable screens while falling back to the SDR base layer everywhere else.
Rendering and CGI
HDR images are not limited to photography. 3D rendering engines like Blender, Unreal Engine, and Cinema 4D can output HDR images natively in EXR or HDR radiance formats. Product visualization, architectural rendering, and game-engine screenshots can all produce genuine HDR content that benefits from HDR display capabilities on the web.
HDR vs SDR: Key Differences
Understanding the differences between HDR and SDR is fundamental to implementing HDR images on the web correctly.
Luminance Range
SDR content is mastered to a reference white of around 80-100 nits. Everything in the image is mapped relative to that ceiling. An SDR display simply cannot show anything brighter than its peak output, and that peak is treated as “white.”
HDR content breaks this constraint. With PQ encoding, pixel values can represent luminance up to 10,000 nits. On a real HDR display with a peak of, say, 1000 nits, the display’s own tone mapping decides how to render values above its capability. The important point is that specular highlights, light sources, and reflections can be encoded at brightness levels well above the surrounding content, creating a convincing sense of depth and realism.
Color Volume
SDR operates within the sRGB color space, which covers roughly 35% of the colors the human eye can perceive (as defined by the CIE 1931 chromaticity diagram). HDR content typically uses Display P3 (about 25% more coverage than sRGB) or Rec. 2020 (about 75% more coverage). This larger gamut means saturated reds in a sunset, vivid greens in foliage, and deep ocean blues can be represented more accurately.
But color gamut alone is only half the story. HDR also expands the color volume — the three-dimensional space of hue, saturation, and brightness combined. An HDR display can show a saturated red at high luminance, something an SDR panel physically cannot do because driving pixels harder washes out saturation.
Bit Depth and Banding
SDR images are overwhelmingly 8-bit per channel, providing 256 discrete levels per color. This is usually adequate for sRGB content, but it can produce visible banding in smooth gradients (blue skies, studio backdrops). HDR images are encoded at 10-bit or 12-bit per channel, providing 1024 or 4096 levels. Combined with PQ’s perceptually uniform quantization, this virtually eliminates banding.
Practical Comparison
| Aspect | SDR | HDR |
|---|---|---|
| Peak brightness ceiling | ~100 nits | 1000-10,000 nits (format), 400-2000+ nits (display) |
| Color space | sRGB | Display P3, Rec. 2020 |
| Bit depth | 8-bit | 10-bit or 12-bit |
| Banding artifacts | Common in gradients | Virtually eliminated |
| File size (AVIF, comparable quality) | Baseline | 20-50% larger |
| Browser/display requirement | None (universal) | HDR-capable screen + modern browser |
| Metadata | ICC profile | ICC profile + CLLI/MDCV or gain map |
HDR Image Formats
| Format | HDR Support | Browser Support (2026) | Notes |
|---|---|---|---|
| AVIF | Excellent | Chrome 100+, Firefox 113+, Safari 16.4+ | Best overall choice for HDR on the web |
| JPEG XL | Excellent | Safari 17+, Chrome (behind flag removed) | Strong compression, slow adoption |
| HDR HEIF | Good | Safari only (via OS) | Common on Apple devices, poor web reach |
| WebP | No | Wide | No HDR or wide gamut support |
| JPEG | Limited (gain maps) | Gain maps in Safari only | iPhone photos with embedded gain maps |
| PNG | No (practical) | Universal | 16-bit possible but no HDR metadata |
AVIF is currently the best choice for HDR on the web. It supports PQ and HLG transfer functions, 10-bit and 12-bit depth, Display P3 and Rec. 2020 gamuts, and it compresses efficiently. With browser support now covering all major engines, AVIF is the pragmatic default.
HDR Color Spaces Explained
Color spaces define the range of colors available to an image. For HDR web images, three color spaces matter most.
sRGB
The web’s default color space since 1996. sRGB covers a modest gamut roughly equivalent to a typical CRT monitor of that era. All untagged images on the web are assumed to be sRGB. It uses a simple gamma transfer function (approximately 2.2) and an 8-bit encoding. sRGB is the baseline your SDR fallback images should target.
Display P3
Originally developed by Apple for digital cinema (DCI-P3) and adapted for displays, Display P3 uses the same white point as sRGB (D65) but extends the gamut significantly, especially in reds and greens. Display P3 covers about 25% more of the visible spectrum than sRGB. All modern iPhones, iPads, MacBooks, and many flagship Android phones use Display P3 panels. When you serve HDR images for the web, Display P3 is the most practical wide-gamut target because the hardware is widespread.
Rec. 2020
The ITU-R BT.2020 color space was designed for ultra-high-definition television. It covers roughly 75% more of the visible spectrum than sRGB and about 37% more than Display P3. While no consumer display can fully reproduce Rec. 2020 today, encoding HDR images in Rec. 2020 is forward-looking and allows the content to take advantage of future display improvements. Many HDR video workflows use Rec. 2020 with PQ, and AVIF supports this combination natively.
Choosing the Right Color Space
For most web HDR use cases, Display P3 with PQ transfer function is the sweet spot. It matches the actual capability of the vast majority of HDR-capable screens visiting your site. Rec. 2020 is appropriate for archival-quality or cinema-grade content where you want to preserve the widest possible gamut for future displays.
Detecting HDR Displays
CSS Media Queries
/* Target HDR-capable screens */
@media (dynamic-range: high) {
.hero-image {
background-image: url('hero-hdr.avif');
}
}
/* Explicit SDR fallback */
@media (dynamic-range: standard) {
.hero-image {
background-image: url('hero-sdr.jpg');
}
}
/* Target wide-gamut displays (Display P3 or wider) */
@media (color-gamut: p3) {
.product-image {
background-image: url('product-p3.avif');
}
}
/* Target ultra-wide gamut (Rec. 2020 class) */
@media (color-gamut: rec2020) {
.product-image {
background-image: url('product-rec2020.avif');
}
}
/* Combine conditions for precise targeting */
@media (dynamic-range: high) and (color-gamut: p3) {
.hero-banner {
background-image: url('banner-hdr-p3.avif');
}
}
JavaScript Detection
function getDisplayCapabilities() {
return {
hdr: window.matchMedia('(dynamic-range: high)').matches,
p3: window.matchMedia('(color-gamut: p3)').matches,
rec2020: window.matchMedia('(color-gamut: rec2020)').matches,
prefersContrast: window.matchMedia('(prefers-contrast: high)').matches,
screenBrightness: screen.colorDepth // 24 for 8-bit, 30 for 10-bit
};
}
const capabilities = getDisplayCapabilities();
if (capabilities.hdr && capabilities.p3) {
loadHDRImages();
} else if (capabilities.p3) {
// Wide gamut but not HDR -- serve P3 SDR images
loadWideGamutImages();
} else {
loadSDRImages();
}
// Listen for display changes (e.g., user moves window to a different monitor)
window.matchMedia('(dynamic-range: high)').addEventListener('change', (e) => {
if (e.matches) {
upgradeToHDR();
} else {
downgradeToSDR();
}
});
The change event listener is particularly useful for desktop users who might have a mixed-monitor setup. When they drag a browser window from an SDR monitor to an HDR monitor, your site can respond dynamically.
Serving HDR Images
Picture Element Approach
The <picture> element gives you the most control over HDR image delivery. You can combine media queries, format negotiation, and resolution switching in a single declaration.
<picture>
<!-- HDR AVIF for HDR displays -->
<source
media="(dynamic-range: high)"
srcset="sunset-hdr.avif"
type="image/avif"
>
<!-- SDR AVIF for wide browser support -->
<source srcset="sunset-sdr.avif" type="image/avif">
<!-- WebP fallback -->
<source srcset="sunset.webp" type="image/webp">
<!-- JPEG ultimate fallback -->
<img src="sunset.jpg" alt="Vibrant sunset over mountains">
</picture>
For responsive images, combine HDR detection with resolution switching:
<picture>
<source
media="(dynamic-range: high)"
srcset="hero-hdr-800.avif 800w,
hero-hdr-1200.avif 1200w,
hero-hdr-1920.avif 1920w"
sizes="100vw"
type="image/avif"
>
<source
srcset="hero-sdr-800.avif 800w,
hero-sdr-1200.avif 1200w,
hero-sdr-1920.avif 1920w"
sizes="100vw"
type="image/avif"
>
<img
src="hero-sdr-1200.jpg"
srcset="hero-sdr-800.jpg 800w,
hero-sdr-1200.jpg 1200w,
hero-sdr-1920.jpg 1920w"
sizes="100vw"
alt="Mountain landscape at golden hour"
loading="lazy"
decoding="async"
>
</picture>
Using Image CDNs
Sirv can serve optimized images automatically, handling format negotiation and quality tuning on the server side:
<!-- Sirv auto-selects the best format for the requesting browser -->
<img src="https://your-site.sirv.com/photos/sunset.jpg?format=optimal&q=auto">
With a CDN like Sirv, you upload a single high-quality source file and the CDN generates the appropriate AVIF, WebP, or JPEG variant based on the browser’s Accept header. This dramatically simplifies HDR delivery because you can upload your HDR master and let the CDN handle format negotiation.
Content Negotiation via Server Headers
If you manage your own server, you can use the Accept header and client hints to serve HDR content:
// Express.js middleware example
app.get('/images/:name', (req, res) => {
const acceptsAvif = req.headers.accept?.includes('image/avif');
const supportsHDR = req.headers['sec-ch-prefers-color-scheme']; // future hint
const imageName = req.params.name;
if (acceptsAvif) {
// Serve AVIF (which may include HDR data)
res.type('image/avif');
res.sendFile(`${imageName}.avif`);
} else {
res.type('image/jpeg');
res.sendFile(`${imageName}.jpg`);
}
});
Creating HDR Images for the Web
Adobe Photoshop
Photoshop supports HDR output via the Export As dialog. To create an HDR AVIF:
- Open your image or merge HDR brackets via File > Automate > Merge to HDR Pro.
- Work in 16-bit or 32-bit mode with a Display P3 or Rec. 2020 profile (Edit > Convert to Profile).
- Export via File > Export As, select AVIF format.
- In the export dialog, ensure the color profile is set to Display P3 and bit depth is 10-bit or higher.
- Save a second copy as an sRGB JPEG or sRGB AVIF for your SDR fallback.
Adobe Lightroom
Lightroom Classic and Lightroom CC can both produce HDR output:
- Select bracketed photos and use Photo > Photo Merge > HDR to create a merged DNG.
- Edit the merged HDR DNG with full tonal control.
- Export with the Display P3 color space selected (available in Export dialog under Color Space).
- Choose AVIF as the output format (supported in Lightroom 2025+).
Using ffmpeg
ffmpeg is a powerful command-line tool for converting images between color spaces and formats:
# Convert a 16-bit TIFF to HDR AVIF with PQ transfer function and Display P3 gamut
ffmpeg -i input.tiff \
-pix_fmt yuv444p10le \
-c:v libaom-av1 \
-crf 20 \
-color_primaries bt2020 \
-color_trc smpte2084 \
-colorspace bt2020nc \
output-hdr.avif
# Convert to SDR AVIF for fallback
ffmpeg -i input.tiff \
-pix_fmt yuv444p \
-c:v libaom-av1 \
-crf 24 \
-color_primaries bt709 \
-color_trc iec61966-2-1 \
-colorspace bt709 \
output-sdr.avif
Using libavif (cavif)
The cavif command-line encoder from the libavif project offers fine-grained control over AVIF HDR encoding:
# Encode an HDR image with 10-bit depth and Display P3 gamut
cavif --min 20 --max 28 \
--depth 10 \
--cicp 12/16/9 \
-o output-hdr.avif \
input.png
The --cicp flag sets the color information coding points: 12 for BT.2020 primaries, 16 for PQ transfer, and 9 for BT.2020 non-constant luminance matrix. For Display P3 with PQ, use --cicp 12/16/0.
Batch Conversion Script
For processing multiple images, here is a practical shell script:
#!/bin/bash
# Convert a directory of source images to HDR AVIF + SDR AVIF fallback
SRC_DIR="./source"
OUT_DIR="./output"
mkdir -p "$OUT_DIR"
for img in "$SRC_DIR"/*.tiff; do
base=$(basename "$img" .tiff)
# HDR version
ffmpeg -i "$img" \
-pix_fmt yuv444p10le \
-c:v libaom-av1 -crf 22 \
-color_primaries bt2020 \
-color_trc smpte2084 \
-colorspace bt2020nc \
"$OUT_DIR/${base}-hdr.avif" -y
# SDR fallback
ffmpeg -i "$img" \
-vf "tonemap=tonemap=hable:peak=10" \
-pix_fmt yuv444p \
-c:v libaom-av1 -crf 26 \
-color_primaries bt709 \
-color_trc iec61966-2-1 \
-colorspace bt709 \
"$OUT_DIR/${base}-sdr.avif" -y
done
Tone Mapping for SDR Fallbacks
Every HDR image you serve on the web needs an SDR fallback. Tone mapping is the process of compressing the extended luminance and gamut of an HDR image down into the SDR range while preserving as much visual quality as possible.
Why Tone Mapping Matters
Without a properly tone-mapped fallback, SDR users may see washed-out, low-contrast, or oddly colored images. An HDR image displayed on an SDR screen without tone mapping typically looks flat because the display cannot reproduce the highlight detail and simply clips everything above its peak brightness.
Tone Mapping Algorithms
Several algorithms are commonly used:
- Reinhard: A simple global operator that compresses the entire luminance range. Produces natural-looking results but can reduce local contrast.
- Hable (Uncharted 2): A filmic curve that preserves highlight rolloff. Popular in game engines and video production.
- ACES (Academy Color Encoding System): An industry-standard approach that handles wide gamut and high dynamic range gracefully. Used in film post-production.
- Display-referred clipping: The simplest approach — just clip values above SDR white. Produces harsh highlights but is zero-effort.
Generating SDR Fallbacks with ffmpeg
# Tone map from HDR (PQ/BT.2020) to SDR (sRGB) using the Hable operator
ffmpeg -i hdr-input.avif \
-vf "zscale=t=linear:npl=100,tonemap=hable:peak=10:desat=0,\
zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
-c:v libaom-av1 -crf 26 \
sdr-output.avif
CSS-Based Tone Mapping (Future)
The CSS Color Level 4 specification introduces color() and color-mix() functions that are color-space aware. While CSS cannot tone-map images directly, it ensures that CSS colors declared in wide-gamut spaces (like Display P3) gracefully fall back on SDR screens:
.highlight-badge {
/* Display P3 vibrant red, with sRGB fallback automatically computed */
background-color: color(display-p3 1 0.2 0.1);
}
Performance Considerations
HDR images are typically larger than their SDR equivalents due to higher bit depth and wider gamut data:
| Version | Format | Quality | Size | Notes |
|---|---|---|---|---|
| SDR | AVIF 65% | Good | 95 KB | 8-bit, sRGB |
| HDR | AVIF 65% | Good | 140 KB | 10-bit, Display P3 |
| SDR | JPEG 80% | Good | 210 KB | Baseline comparison |
| HDR | JPEG XL 75% | Good | 125 KB | 10-bit, Display P3 |
The roughly 30-50% size increase for HDR AVIF over SDR AVIF is a meaningful consideration for mobile users on metered connections. Prioritize HDR for hero images, product photography, and portfolio showcases where the visual impact justifies the extra bytes.
Loading Strategy
const isHDR = window.matchMedia('(dynamic-range: high)').matches;
const imageSrc = isHDR ? '/hero-hdr.avif' : '/hero-sdr.avif';
// Preload the chosen variant
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'image';
link.href = imageSrc;
link.type = 'image/avif';
document.head.appendChild(link);
Lazy Loading HDR Content
For below-the-fold images, combine native lazy loading with HDR detection:
<picture>
<source
media="(dynamic-range: high)"
srcset="gallery-01-hdr.avif"
type="image/avif"
>
<source srcset="gallery-01-sdr.avif" type="image/avif">
<img
src="gallery-01.jpg"
alt="Gallery image"
loading="lazy"
decoding="async"
width="800"
height="600"
>
</picture>
Including explicit width and height attributes prevents layout shift regardless of which variant loads.
Testing HDR Content
Properly testing HDR images requires both real hardware and software simulation.
Chrome DevTools
Chrome DevTools can simulate HDR and color gamut capabilities:
- Open DevTools (F12 or Cmd+Option+I).
- Open the Rendering panel (three-dot menu > More tools > Rendering).
- Under “Emulate CSS media feature
dynamic-range”, selecthighto simulate an HDR display. - Under “Emulate CSS media feature
color-gamut”, selectp3orrec2020. - Reload the page and verify that your HDR
<picture>sources and CSS media queries activate correctly.
Note that DevTools simulation only triggers the media queries — it does not actually render HDR luminance levels. The images will load but will appear in SDR on an SDR screen. This is useful for testing your detection logic but not for evaluating visual quality.
Safari Web Inspector
On macOS, Safari’s Web Inspector includes color gamut emulation. Since Macs with XDR displays (MacBook Pro, Pro Display XDR) are among the best HDR display options for development, Safari on these machines will render actual HDR luminance from PQ-encoded AVIF images.
Real Device Testing
There is no substitute for testing on actual HDR hardware. Recommended test devices:
- iPhone 14/15/16 Pro — Excellent HDR rendering in Safari and Chrome, 1600-2000 nit peak
- MacBook Pro (M-series) — XDR display, 1600 nit peak sustained HDR, ideal for desktop testing
- Samsung Galaxy S24/S25 — HDR10+ support, tests Android Chrome behavior
- External HDR monitor — An HDR600 or HDR1000-certified monitor connected to a desktop helps test Windows/Linux rendering
Automated Visual Testing
For CI pipelines, you can verify that your <picture> elements include the correct HDR sources:
// Playwright test example
const { test, expect } = require('@playwright/test');
test('hero image serves HDR AVIF on HDR displays', async ({ page }) => {
// Emulate an HDR-capable display
await page.emulateMedia({ colorScheme: 'dark' });
// Note: Playwright can set media features
await page.addInitScript(() => {
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: (query) => ({
matches: query === '(dynamic-range: high)' || query === '(color-gamut: p3)',
media: query,
addEventListener: () => {},
removeEventListener: () => {},
}),
});
});
await page.goto('/');
const heroSource = page.locator('picture source[media="(dynamic-range: high)"]');
await expect(heroSource).toHaveAttribute('srcset', /hdr\.avif/);
});
Common HDR Pitfalls
Implementing HDR images on the web involves several common mistakes that can degrade the experience for both HDR and SDR users.
Oversaturation
One of the most frequent problems with HDR photography is pushing saturation too far during editing. On an HDR display with a wide gamut, highly saturated colors can appear garish or unnatural. On an SDR display viewing a tone-mapped fallback, oversaturated source material produces clipped, posterized colors. Keep saturation adjustments moderate and check your images on both HDR and SDR screens.
Highlight Clipping in Fallbacks
If your SDR fallback is created by a naive clip of HDR luminance values rather than proper tone mapping, highlights will be harsh white blobs. Always use a proper tone mapping operator (Reinhard, Hable, or ACES) to create fallbacks, or use tools like Lightroom and Photoshop that handle the conversion gracefully.
Washed-Out SDR Appearance
This happens when an HDR image with PQ transfer function is served to an SDR display without tone mapping. The display interprets the PQ values using its sRGB gamma curve, which compresses the tonal range and produces a flat, washed-out image. The solution is to always serve a separate SDR rendition to SDR screens, never the raw HDR file.
Mismatched Color Profiles
Serving a Display P3 image without an embedded ICC profile (or with an incorrect profile) can cause the browser to interpret it as sRGB, shifting colors. Always embed the correct ICC profile in your HDR images and verify it with tools like exiftool or ImageMagick’s identify -verbose.
# Check the color profile of an AVIF file
exiftool -ColorSpace -ColorPrimaries -TransferCharacteristics image.avif
Ignoring Data Saver Mode
Some users enable data saver or low-bandwidth modes. Serving a 140 KB HDR AVIF when the user is on a metered connection with data saver enabled is poor practice. Consider respecting the Save-Data client hint:
const saveData = navigator.connection?.saveData;
const isHDR = window.matchMedia('(dynamic-range: high)').matches;
// Only serve HDR if the user is not in data saver mode
const useHDR = isHDR && !saveData;
Not Testing Without HDR
Developers with HDR displays may never see their SDR fallback path. Use Chrome DevTools to emulate (dynamic-range: standard) and verify that your fallback images look correct, load properly, and do not show the HDR variant.
Best Practices
1. Always Provide Fallbacks
Never serve only an HDR image. Always include an SDR fallback that looks good on conventional displays.
<picture>
<source media="(dynamic-range: high)" srcset="hdr.avif" type="image/avif">
<source srcset="sdr.avif" type="image/avif">
<img src="fallback.jpg" alt="Description">
</picture>
2. Respect User Preferences
Some users set high-contrast or reduced-motion preferences for accessibility. HDR’s extreme brightness range can be uncomfortable for users with photosensitivity. Respect the prefers-contrast media query:
@media (prefers-contrast: high) {
.hero {
background-image: url('hero-sdr.jpg');
}
}
3. Test on Real Devices
Test on iPhone 12+, MacBook Pro with XDR display, and HDR monitors with proper calibration. DevTools emulation tests your detection logic but cannot show you the actual HDR rendering.
4. Optimize File Sizes
HDR images carry more data. Be deliberate about where you use HDR — hero images, featured product photos, and portfolio pieces benefit most. Thumbnails and UI elements rarely need HDR.
5. Use Appropriate Quality Settings
HDR AVIF at quality 60-70 typically provides an excellent balance of visual quality and file size. Do not default to maximum quality; the perceptual difference above quality 75 is negligible for most content while file sizes increase significantly.
6. Monitor Display Changes
Desktop users with multiple monitors may move your site between HDR and SDR displays. Listen for media query changes and swap images dynamically:
const hdrQuery = window.matchMedia('(dynamic-range: high)');
hdrQuery.addEventListener('change', (e) => {
document.querySelectorAll('[data-hdr-src]').forEach((img) => {
img.src = e.matches ? img.dataset.hdrSrc : img.dataset.sdrSrc;
});
});
Conclusion
HDR on the web is becoming practical, and the tools, formats, and browser support have matured enough for production use:
- AVIF is the best format for HDR web images today, with broad browser support and excellent compression
- Detect capabilities with CSS media queries and JavaScript to serve the right variant to each device
- Always provide fallbacks for SDR displays — tone map your HDR content into quality SDR versions
- Use CDNs like Sirv to simplify delivery and format negotiation
- Test on real devices — emulation verifies logic, but only real HDR displays show actual rendering quality
- Watch your file sizes — HDR adds bytes, so be selective about which images get the HDR treatment
- Respect user preferences — accessibility settings and data saver mode should influence your serving strategy
HDR photography and HDR display technology are converging on the web. By implementing HDR images thoughtfully — with proper format selection, robust detection, careful tone mapping, and thorough testing — you can deliver dramatically better visual experiences to the growing majority of users with HDR-capable screens, while ensuring everyone else still sees great-looking content.