Guides7 min read·

Device pixel ratio (DPR) explained, with real devices

Device pixel ratio is how many screen pixels make one CSS pixel. See the real DPR of iPhones, Galaxies, Pixels and MacBooks, and how to stop blurry images.

Device pixel ratio (DPR) is the number of physical screen pixels used to draw one CSS pixel, in each direction. An iPhone 17 Pro has a DPR of 3, so a 100×100 CSS box is drawn with 300×300 real pixels. You can read it in JavaScript with window.devicePixelRatio, and it's the main reason an image looks crisp on one screen and blurry on another.

If you're fuzzy on CSS pixels vs physical pixels, start with What is a viewport? and come back. This post is about the ratio between them.

DPR by device

The ratio is simple: physical width ÷ CSS width. Here's the spread across real devices, all numbers at factory settings:

DPR Examples (CSS viewport)
1 24″ Full HD monitor (1920×1080), HD laptop (1366×768), 27″ QHD monitor (2560×1440)
1.25 15.6″ Full HD laptop @ 125% (1536×864), Chromebook Full HD (1536×864)
1.5 14″ WUXGA laptop @ 150% (1280×800), 4K monitor @ 150% (2560×1440), Galaxy Tab A9+ (800×1280)
1.75 Moto G (2025) (412×917)
2 iPhone SE (375×667), every iPad, every MacBook, Studio Display (2560×1440)
2.25 Pixel 10 Pro XL (448×998)
2.4375 Moto G Power (2025) (444×980)
2.5 Moto G Stylus 5G (2024) (432×960)
2.53125 Pixel 10 Pro (427×952)
2.625 Pixel 10 (412×924), Galaxy Z Fold 7 cover (412×960)
2.75 Redmi Note 13 (393×873)
2.8125 Galaxy S25 Ultra (384×832), Galaxy A56 / A36 (384×832)
3 iPhone 17 Pro (402×874), Galaxy S25 (360×780), Xiaomi 15 (400×890)

Browse the full lists on the iPhone, Samsung Galaxy and Google Pixel pages.

DPR 1, 2 and 3

DPR 1 is the old world: one CSS pixel, one physical pixel. You still see it on plenty of desktop monitors and cheap laptops. If an image looks fine at DPR 1, it's the right size for DPR 1 and no more.

DPR 2 arrived with Apple's Retina displays and is now standard on iPads, MacBooks, Apple's external displays and many tablets. Each CSS pixel is a 2×2 block, so an image needs twice the width and height (four times the pixels) to look as sharp.

DPR 3 is where modern phones live. Every current iPhone is 3, and so is the base Galaxy S25. A 3× image has 9 times the pixels of a 1× one.

Fractional DPRs on Android and Windows

Look at that table again: 2.625, 2.8125, 2.53125. These aren't typos.

Android defines its density-independent pixel as one physical pixel on a 160 dpi screen, so a phone's DPR is its density setting divided by 160 (Android docs). A Pixel 10 at 420 dpi gets 420 ÷ 160 = 2.625. A Galaxy at 450 dpi gets 2.8125.

Two knock-on effects:

  • CSS sizes get rounded. The Pixel 10 has 1080 physical pixels across. 1080 ÷ 2.625 = 411.4, and Chrome on Android rounds that up to a 412px viewport.
  • Settings change the DPR. Samsung's Display size setting changes the ratio, not just the layout. A Galaxy S25 is 360px wide at DPR 3 by default, 384px at 2.8125 on "smaller", and 320px at 3.375 on "largest".

Watch out for one more wrinkle: physical pixels ÷ CSS width doesn't always equal the DPR. The Galaxy S25 Ultra has a 1440×3120 panel, but by default it renders pages at 384 × 2.8125 = 1080 pixels across. Switch on "Full WQHD+ resolution" in settings and it becomes 385px wide at DPR 3.75.

Windows does the same thing with display scaling. At 125%, 150% and 175%, the DPR is 1.25, 1.5 and 1.75. A 16″ 2560×1600 laptop at 150% gives websites 2560 ÷ 1.5 = 1706.7, rounded up to 1707×1067. More in Windows display scaling and the 1536×864 viewport.

Reading DPR in JavaScript

console.log(window.devicePixelRatio); // 3 on an iPhone 17 Pro, 1.25 on a Full HD laptop at 125%

DPR can change while the page is open: someone zooms, or drags the window from a laptop screen to an external monitor. MDN's devicePixelRatio page suggests watching a resolution media query:

function watchDpr() {
  const mq = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
  mq.addEventListener('change', () => {
    console.log('DPR is now', window.devicePixelRatio);
    watchDpr(); // set up a new watcher for the new value
  }, { once: true });
}
watchDpr();

You only need this for things you draw yourself, like a <canvas> chart. Everything else the browser handles.

Why images look blurry

Say you drop a 400px-wide image into a 400px-wide slot. On a DPR 1 monitor, perfect. On an iPhone 17 Pro, the slot is 400 CSS pixels but 1200 physical pixels wide. The browser only has 400 pixels of image, so it stretches each one across three. That's the soft, slightly smeared look.

The fix is one multiplication:

image pixels needed = displayed CSS width × DPR

For a full-width image (a hero, a banner), with the browser window maximized on desktop:

Device CSS width DPR Image width needed
iPhone SE (2nd & 3rd gen) 375 2 750
Moto G (2025) 412 1.75 721
Galaxy S25 360 3 1080
Galaxy S25 Ultra 384 2.8125 1080
Pixel 10 412 2.625 ~1082
iPhone 17 Pro 402 3 1206
iPhone 17 Pro Max 440 3 1320
iPad Air 11″ 820 2 1640
15.6″ Full HD laptop @ 125% 1536 1.25 1920
MacBook Air 13″ 1470 2 2940
Studio Display 27″ 2560 2 5120

Notice the MacBook Air: it wants a 2940px image even though its panel is only 2560 pixels wide. The browser works at DPR 2 on a 1470px viewport, and macOS scales the result down to the panel afterwards. The browser doesn't know or care.

Also notice that a phone often needs a bigger file than a Full HD laptop. A 402px iPhone wants 1206 pixels. That's why "mobile images can be small" is a myth.

Whether you go all the way to 3× is a judgement call. A 3× image has 2.25 times the pixels of a 2× one, and on photos the difference is hard to spot. For logos, icons and anything with text in it, skip the question entirely and use SVG, which is sharp at every DPR.

Serving the right image for each DPR

In HTML: srcset

For <img> tags, srcset lets the browser pick the right file for its DPR:

<img src="/logo-160.png"
     srcset="/logo-160.png 1x, /logo-320.png 2x, /logo-480.png 3x"
     width="160" height="40" alt="Acme">

For images that change size with the layout, use w descriptors and sizes instead. That's a whole topic, covered step by step in Responsive images with srcset and sizes.

In CSS: resolution media queries

.badge { background-image: url("/badge-1x.png"); }

@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
  .badge { background-image: url("/badge-2x.png"); }
}

dppx means "dots per CSS pixel", which is the DPR. The -webkit- line is for older Safari versions, which only understood the prefixed form. See MDN's resolution media feature.

In CSS: image-set()

image-set() is the srcset of CSS backgrounds:

.hero {
  background-image: url("/hero-1x.jpg"); /* fallback for very old browsers */
  background-image: image-set(
    url("/hero-1x.jpg") 1x,
    url("/hero-2x.jpg") 2x,
    url("/hero-3x.jpg") 3x
  );
}

The browser picks the best match for its DPR. It's supported unprefixed in current major browsers (MDN: image-set()).

On canvas

A <canvas> is a bitmap, so it has the same problem. Size its backing store in physical pixels and scale the drawing context:

const canvas = document.querySelector('canvas');
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();

canvas.width = Math.round(rect.width * dpr);
canvas.height = Math.round(rect.height * dpr);

const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr); // now draw in CSS pixels as usual

Browser zoom changes DPR (on desktop)

Here's one that trips people up when testing. In Chrome, Edge and Firefox on desktop, browser zoom changes devicePixelRatio and shrinks the viewport.

So if your images look oddly sharp or your layout jumps to the tablet version on your own laptop, check you haven't left the browser zoomed. Pinch-zoom on a phone is different: it magnifies the visual viewport and leaves devicePixelRatio alone.

This also matters for testing tools. Browser-based previews like doesitfit draw everything with your computer's DPR. They get the CSS layout right, but a 1× image previewed on a DPR 2 MacBook won't look the way it does on a DPR 3 iPhone. Use the table above for image sizes, and see why DevTools device mode isn't accurate for the other gaps.

Does your site fit?

Paste your address (or localhost:3000). doesitfit shows it on real screen sizes at once and tells you, bluntly, where it spills.

Free, no sign-up. Or ask Claude, ChatGPT or Codex to check it.

What to do with this

  1. Design and code in CSS pixels. DPR is the browser's problem, except for bitmaps.
  2. Size images as CSS width × DPR. For a full-width phone image that's roughly 1080 to 1320 pixels; for a full-width laptop image, 1920 to 2940.
  3. Use srcset for <img> and image-set() for backgrounds, so DPR 1 screens don't download 3× files.
  4. Use SVG for logos and icons. No DPR maths at all.
  5. Scale your canvas by devicePixelRatio if you draw charts or games.
  6. Reset your browser zoom to 100% before judging a layout on your own machine.

Questions people ask

What is the device pixel ratio of an iPhone?

All iPhone 12 to iPhone 18 models, including the mini, Plus, Pro, Pro Max, Air, e and Duo versions, have a DPR of 3. The iPhone 11 / XR and the iPhone SE (2nd and 3rd gen) use 2.

Does a higher DPR make my website look smaller?

No. CSS sizes stay the same; a higher DPR just uses more physical pixels to draw each CSS pixel, so text and images look sharper, not smaller.

Can the user change their device pixel ratio?

Yes, in several ways. Browser zoom on desktop and the operating system's display scaling both change it, and on Samsung phones the Display size setting does too. On iPhone, Display Zoom changes the viewport (for example to 320×693) but the DPR stays 3.

Why does my screenshot of a website look so big?

Screenshots are taken in physical pixels. A screenshot of a 402px-wide page on an iPhone 17 Pro is 1206 pixels wide because the DPR is 3. Halve or third it before using it as a design reference.

Keep reading