Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.
ImagesMedium

Support high-DPI retina displays

High-resolution images (2x, 3x) are provided for retina and high-DPI displays.

Utilities
Quick take
Typical fix time 15 min
  • Provide 2x and 3x images for high-DPI displays
  • Use srcset with x descriptors for fixed-size images
  • Use srcset with w descriptors for responsive images
  • CSS background-image: use image-set() or media queries
Why it matters: Standard images look blurry on retina displays (2x, 3x pixel density)—high-resolution assets ensure sharp visuals on modern devices.

Rule Details

High-DPI displays need higher resolution images to appear sharp.

Code Example

<!-- For images displayed at fixed pixel size -->
<img
  src="logo.png"
  srcset="
    logo.png 1x,
    logo@2x.png 2x,
    logo@3x.png 3x
  "
  alt="Logo"
  width="200"
  height="50"
>

Why It Matters

Standard images look blurry on retina displays (2x, 3x pixel density)—high-resolution assets ensure sharp visuals on modern devices.

Understanding Pixel Density

DevicePixel RatioImage Needed
Standard displays1x100px image for 100px element
Retina (most phones)2x200px image for 100px element
iPhone Pro, high-end Android3x300px image for 100px element

srcset with w Descriptors (Responsive)

<!-- For responsive images, w descriptors are preferred -->
<img
  src="hero-800.jpg"
  srcset="
    hero-400.jpg 400w,
    hero-800.jpg 800w,
    hero-1200.jpg 1200w,
    hero-1600.jpg 1600w
  "
  sizes="(max-width: 600px) 100vw, 50vw"
  alt="Hero image"
>
<!-- Browser calculates based on viewport AND pixel density -->

CSS Background Images

/* Using image-set() */
.hero {
  background-image: url('hero.jpg');
  background-image: image-set(
    url('hero.jpg') 1x,
    url('hero@2x.jpg') 2x,
    url('hero@3x.jpg') 3x
  );
}
 
/* Using media queries (broader support) */
.logo {
  background-image: url('logo.png');
}
 
@media (-webkit-min-device-pixel-ratio: 2),
       (min-resolution: 192dpi) {
  .logo {
    background-image: url('logo@2x.png');
    background-size: 200px 50px; /* Original dimensions */
  }
}
 
@media (-webkit-min-device-pixel-ratio: 3),
       (min-resolution: 288dpi) {
  .logo {
    background-image: url('logo@3x.png');
    background-size: 200px 50px;
  }
}

React Retina Image Component

interface RetinaImageProps {
  src: string
  alt: string
  width: number
  height: number
  className?: string
}
 
function RetinaImage({ src, alt, width, height, className }: RetinaImageProps) {
  // Generate retina versions from base path
  const basePath = src.replace(/\.[^.]+$/, '')
  const extension = src.match(/\.[^.]+$/)?.[0] || '.png'
 
  return (
    <img
      src={src}
      srcSet={`
        ${src} 1x,
        ${basePath}@2x${extension} 2x,
        ${basePath}@3x${extension} 3x
      `}
      alt={alt}
      width={width}
      height={height}
      className={className}
    />
  )
}

Next.js Automatic Retina Support

import Image from 'next/image'
 
// Next.js automatically generates srcset for different DPRs
function Logo() {
  return (
    <Image
      src="/logo.png"
      alt="Logo"
      width={200}
      height={50}
      // Automatically serves 1x, 2x sizes based on device
    />
  )
}

Generating Retina Assets

// Sharp script to generate 1x, 2x, 3x versions
const sharp = require('sharp')
 
async function generateRetinaVersions(inputPath, baseName) {
  const sizes = [
    { suffix: '', scale: 1 },
    { suffix: '@2x', scale: 2 },
    { suffix: '@3x', scale: 3 }
  ]
 
  const metadata = await sharp(inputPath).metadata()
  const baseWidth = metadata.width / 3 // Assume input is 3x
 
  for (const { suffix, scale } of sizes) {
    await sharp(inputPath)
      .resize(Math.round(baseWidth * scale))
      .toFile(`${baseName}${suffix}.png`)
  }
}

SVG for Resolution Independence

<!-- SVG scales perfectly to any DPR -->
<img src="logo.svg" alt="Logo" width="200" height="50">
 
<!-- Inline SVG also scales -->
<svg width="200" height="50" viewBox="0 0 200 50">
  <!-- Vector content -->
</svg>

Icon Fonts and SVG Icons

// SVG icons are naturally resolution-independent
function Icon({ name, size = 24 }: { name: string; size?: number }) {
  return (
    <svg width={size} height={size} aria-hidden="true">
      <use href={`/icons.svg#${name}`} />
    </svg>
  )
}

Verification

  1. Toggle device pixel ratio in Chrome DevTools (Settings → Experiments → Device)
  2. Use Responsive Design Mode in Safari (Retina option)
  3. Test on actual retina devices
  4. Verify correct image loads in Network tab
  5. Check that images appear sharp, not blurry
File Size Balance

3x images are 9x the pixels of 1x images. Consider whether 3x is necessary—2x often provides sufficient sharpness while saving significant bandwidth.

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Check if high-resolution images are provided for retina displays (2x, 3x).

Fix

Auto-fix issues

Add retina-ready images using srcset or CSS image-set for high-DPI displays.

Explain

Learn more

Explain how retina images ensure sharp visuals on high-density displays.

Review

Code review

Review image assets, markup, and delivery configuration related to Support high-DPI retina displays. Flag exact files or components where format choice, sizing, or loading behavior violates the rule, and describe how to confirm the fix in DevTools.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

Squoosh
squoosh.appTool

Rules that often go hand-in-hand with this one.

Implement responsive images with srcset

Images use srcset and sizes attributes for responsive delivery across devices.

Images
Use srcset for responsive images

Images wider than 100px use the srcset attribute to offer multiple resolution variants, letting the browser download the optimal size for the user's viewport and device pixel ratio.

Images
Use container queries for component-level responsiveness

Use CSS container queries to make components respond to their own container's size rather than the viewport, enabling truly reusable responsive components.

CSS
Prevent horizontal scrolling

Web pages must not require horizontal scrolling at standard viewport widths. Horizontal overflow breaks responsive layouts and makes content inaccessible to low-vision users who zoom in.

CSS

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385