How to Make Images Sharp on Retina Screens

To make images sharp on retina screens, export them at twice their displayed CSS size and serve them with srcset so the browser picks the right file for each screen. Use SVG for logos and icons, which stay sharp at any pixel density.

Why images look blurry on high-density screens

A "retina" or high-density screen uses more than one physical pixel to draw each CSS pixel. If you place a 400-pixel-wide image in a 400px-wide slot on a 2x screen, the browser has 800 device pixels to fill, so it stretches each image pixel across a 2 × 2 block. The result is soft edges and fuzzy text inside the image.

The fix is to give the browser more pixels than the layout size, but only to screens that can use them.

CSS pixels vs device pixels

CSS pixels are the units you write in your stylesheet. Device pixels are the physical dots on the screen. The ratio between them is the device pixel ratio (DPR):

device pixels = CSS pixels × device pixel ratio

Device typeTypical DPRA 400px-wide image needs
Standard desktop monitor1400 px
Windows laptop with display scaling1.25 to 1.5500 to 600 px
MacBook, many tablets2800 px
Many recent phones2 to 3 (some Android devices use values like 2.625)800 to 1200 px

You can see the value for any screen with window.devicePixelRatio in the browser console. On desktop it changes with browser zoom too, which is another reason to let the browser choose the file. The physical sharpness of the screen itself is its PPI, which you can work out with the PPI calculator; our DPI vs PPI guide explains how the two ideas relate.

Fixed-size images: srcset with x descriptors

When an image always displays at the same CSS size, such as a logo or an avatar, list one file per density with x descriptors.

<img
  src="logo-200.png"
  srcset="logo-200.png 1x, logo-400.png 2x"
  width="200" height="60"
  alt="Acme Studio">

A 1x screen downloads logo-200.png, a 2x screen downloads logo-400.png, and screens in between pick whichever the browser decides is best. The width and height attributes stay at the CSS size (200 × 60), which reserves space and prevents layout shift.

Flexible images: srcset with w descriptors and sizes

Most content images change size with the layout. For those, describe each file by its real pixel width using w, and tell the browser how wide the image will display using sizes.

<img
  src="photo-800.jpg"
  srcset="photo-480.jpg 480w,
          photo-800.jpg 800w,
          photo-1200.jpg 1200w,
          photo-1600.jpg 1600w,
          photo-2400.jpg 2400w"
  sizes="(min-width: 1200px) 800px, (min-width: 768px) 66vw, 100vw"
  width="1600" height="1067"
  loading="lazy"
  alt="Designer sketching wireframes on a tablet">

The sizes attribute reads like a set of media queries. This one says: on screens 1200px and wider the image is 800px wide; from 768px it takes 66% of the viewport; otherwise it fills the viewport. The browser multiplies that slot width by the device pixel ratio and picks the closest suitable file from srcset.

Some details that trip people up:

  • If you use w descriptors without sizes, the browser assumes the image is 100vw and may download a file far larger than needed.
  • sizes is evaluated before CSS loads, so you have to describe the layout in it yourself; it can't read your stylesheet.
  • Browsers treat srcset as a set of hints. They may pick a smaller file on a slow connection, or keep using a large file already in cache. Don't depend on an exact choice.

The web.dev responsive images lesson covers more edge cases, including art direction.

Worked example: a blog image

An article image sits in a content column that is 720 CSS pixels wide on desktop and full width on phones.

  1. Desktop at 2x: 720 × 2 = 1440 device pixels.
  2. Large phone at 3x: a 430px-wide viewport × 3 = 1290 device pixels.
  3. Standard monitor at 1x: 720 device pixels.
  4. Export: 720, 1080 and 1440 pixels wide covers these cases. The image resize calculator gives the matching heights for each width so the aspect ratio stays exact.
  5. Markup: sizes="(min-width: 760px) 720px, 100vw" (with 760px allowing for page padding).

What sizes to export

Image typeRecommended exportsNotes
Logos, icons, simple illustrationsSVGOne file, sharp at every density
Small raster icons, avatars, thumbnails1x, 2x, and 3x3x adds little weight at small sizes
Fixed-size product or team photos1x and 2xUse x descriptors
Content and hero photos3 to 5 widths, for example 640, 960, 1280, 1920, 2560Use w descriptors and sizes
Screenshots with text1x and 2x, PNG or lossless WebPText shows blur most clearly

Why stop at 2x for photos? Most people can't tell 2x from 3x for photographs at normal viewing distances, but a 3x file has 2.25 times as many pixels as a 2x file. For a large hero image, that can be hundreds of extra kilobytes for little visible gain.

Use SVG for logos and icons

SVG describes shapes mathematically instead of storing pixels, so it renders crisply at any size and any pixel ratio. A logo saved as SVG is often only a few kilobytes and needs no srcset at all. Keep raster formats for photos and complex artwork where SVG would be heavy or impossible. Always set width and height (or a CSS size) on SVG images so they don't render at an unexpected default size.

The file-size trade-off

Doubling the width and height of an image quadruples the pixel count. A 2x image is not automatically four times the file size, because compression works better on larger, smoother images, but it is always noticeably bigger. A few ways to keep it under control:

  • Use modern formats. AVIF and WebP are usually smaller than JPEG at similar quality. The <picture> element lets you offer them with a fallback.
  • Compress 2x images harder. On a high-density screen, compression artifacts are smaller than a CSS pixel, so a lower quality setting on the 2x file is often invisible. Check results by eye.
  • Lazy-load below the fold with loading="lazy", and leave the main hero image eager so it doesn't delay the largest contentful paint.
  • Don't serve the 2x file to everyone. That's the whole point of srcset.
<picture>
  <source type="image/avif" srcset="hero-800.avif 800w, hero-1600.avif 1600w" sizes="100vw">
  <source type="image/webp" srcset="hero-800.webp 800w, hero-1600.webp 1600w" sizes="100vw">
  <img src="hero-1600.jpg" srcset="hero-800.jpg 800w, hero-1600.jpg 1600w"
       sizes="100vw" width="1600" height="900" alt="Studio workspace at sunrise">
</picture>

CSS background images

For decorative backgrounds, image-set() does the same job as x descriptors. Declare a plain fallback first for older browsers.

.banner {
  background-image: url("banner-1x.jpg");
  background-image: image-set(
    url("banner-1x.jpg") 1x,
    url("banner-2x.jpg") 2x
  );
}

Checklist

  1. Logos and icons as SVG wherever possible.
  2. Fixed-size raster images: 1x and 2x with x descriptors.
  3. Flexible images: several widths with w descriptors and an accurate sizes.
  4. width and height on every image to prevent layout shift.
  5. AVIF or WebP where supported, with a JPEG or PNG fallback.
  6. Check sharpness on a real high-density screen, not just a desktop at 1x.

Frequently asked questions

What size should images be for retina displays?

Export images at twice the size they are displayed in CSS pixels. An image shown at 400px wide needs an 800px-wide file to look sharp on a 2x screen. Use srcset so 1x screens can download a smaller version.

Do I need 3x images?

Usually only for small, detailed images like icons or thumbnails, where the extra file size is tiny. For large photos, the difference between 2x and 3x is hard to see and the file can be more than twice as large, so most sites stop at 2x.

What is the difference between x and w descriptors in srcset?

x descriptors (1x, 2x) say which file to use at each device pixel ratio and suit fixed-size images. w descriptors give each file’s actual pixel width and, together with the sizes attribute, let the browser pick the best file for a flexible layout.

How do I check a device’s pixel ratio?

Open the browser console and type window.devicePixelRatio. Many phones report 2 or 3, while Windows laptops commonly report 1.25 or 1.5 because of display scaling. Browser zoom also changes the value on desktop.

Tools for this guide