Understanding Device Pixel Ratio (DPR) for Web Developers
A complete guide to Device Pixel Ratio: what it is, why it matters, and how to build sharp, performant websites for every screen density.
A complete guide to Device Pixel Ratio: what it is, why it matters, and how to build sharp, performant websites for every screen density.
Last updated: February 2026
Device Pixel Ratio (DPR) is the ratio between the physical hardware pixels on a display and the logical (CSS) pixels used by the browser to lay out web content. When Apple introduced the first Retina display on the iPhone 4 in 2010, they doubled the pixel density while keeping the screen physically the same size. To prevent every website and app from shrinking to a quarter of its intended size, they introduced the concept of "points" (logical pixels), where one point mapped to a 2x2 grid of hardware pixels. The browser reports a DPR of 2, telling web developers that each CSS pixel now occupies 4 physical pixels.
This abstraction layer is what allows the same website to work on a 1080p desktop monitor (DPR 1, where CSS pixels and hardware pixels are 1:1) and an iPhone 15 Pro (DPR 3, where each CSS pixel is backed by a 3x3 grid of 9 hardware pixels). Without DPR, text and interface elements would be unreadably small on high-resolution mobile screens.
You can see your current device's pixel ratio alongside its viewport dimensions using the DisplayPixels screen size tool, which reports both CSS pixels and hardware pixels in real time.
Understanding the distinction between CSS pixels and hardware pixels is fundamental to working with DPR.
Hardware pixels are the actual physical light-emitting elements on the display. An iPhone 15 Pro has a screen resolution of 1179 x 2556 hardware pixels. These are fixed by the hardware and never change. You cannot add or remove hardware pixels; they are a physical property of the panel.
CSS pixels are the abstract unit used by web browsers and operating systems for layout. When you write width: 300px in CSS, you are specifying 300 CSS pixels, not 300 hardware pixels. On a DPR 1 display, these are identical. On a DPR 2 display, 300 CSS pixels spans 600 hardware pixels. On a DPR 3 display, it spans 900 hardware pixels.
The CSS pixel is designed to represent roughly the same physical viewing angle regardless of the device. A 16px font on your laptop and a 16px font on your phone should appear approximately the same size to your eyes at their typical viewing distances, even though the phone uses far more hardware pixels to render it.
When JavaScript reports window.innerWidth or when CSS media queries evaluate min-width, they use CSS pixels. The iPhone 15 Pro reports a viewport width of 393 CSS pixels, not 1179. This is the number that matters for layout. The DisplayPixels @media helper shows you exactly what values your browser reports for all of these properties.
DPR values vary across devices and can even vary on the same device depending on operating system scaling settings. Here are the most common values you will encounter.
| Device | DPR |
|---|---|
| Most desktop monitors (1080p, 1440p) | 1 |
| Windows laptops at 125% scaling | 1.25 |
| Windows laptops at 150% scaling | 1.5 |
| MacBook Air / Pro (Retina) | 2 |
| iPad Pro / iPad Air | 2 |
| Samsung Galaxy S series | 2.625 - 3 |
| iPhone 14 / 15 / 16 | 3 |
| iPhone 14/15/16 Pro Max | 3 |
| 4K monitor at 200% scaling | 2 |
Notice that DPR is not always an integer. Windows scaling options produce fractional DPRs like 1.25, 1.5, and 1.75. Some Android devices have DPRs of 2.625 or 3.5. Fractional DPR values can cause sub-pixel rendering artifacts, where the browser must decide how to map a CSS pixel boundary that falls partway through a hardware pixel. This occasionally produces slightly fuzzy lines or borders, though modern browsers handle this well through anti-aliasing.
Images are the most visible area where DPR impacts your website. A bitmap image (JPEG, PNG, WebP) has a fixed pixel grid. When you display a 400x300 image in a 400x300 CSS pixel container on a DPR 2 device, the browser must stretch those 400x300 source pixels across 800x600 hardware pixels. The result is visible blurriness because the browser is interpolating between pixel values rather than having enough source data to fill every hardware pixel.
The solution is to serve images at the appropriate resolution for each device's DPR. For a DPR 2 display, you serve a 2x image (800x600 for a 400x300 container). For DPR 3, you serve a 3x image (1200x900). The browser then has enough pixel data to render sharply at the display's native resolution.
The HTML srcset attribute is the primary mechanism for serving resolution-appropriate images. It lets you specify multiple image sources with their intrinsic widths or pixel densities, and the browser chooses the best one.
<!-- Using pixel density descriptors -->
<img
src="photo-400w.jpg"
srcset="photo-400w.jpg 1x,
photo-800w.jpg 2x,
photo-1200w.jpg 3x"
alt="A landscape photo"
width="400" height="300"
>
<!-- Using width descriptors (more flexible) -->
<img
src="photo-400w.jpg"
srcset="photo-400w.jpg 400w,
photo-800w.jpg 800w,
photo-1200w.jpg 1200w"
sizes="(min-width: 768px) 400px, 100vw"
alt="A landscape photo"
width="400" height="300"
>
The width descriptor approach (400w, 800w) is more flexible because it works with the sizes attribute to account for both DPR and the image's rendered size in the layout. The browser combines the device DPR, the viewport width, and the sizes hint to calculate which source provides the best quality without wasting bandwidth.
The <picture> element provides even more control, allowing you to serve different image formats, aspect ratios, or art-directed crops at different breakpoints.
<picture>
<!-- WebP for browsers that support it -->
<source
type="image/webp"
srcset="photo-400w.webp 400w,
photo-800w.webp 800w,
photo-1200w.webp 1200w"
sizes="(min-width: 768px) 400px, 100vw"
>
<!-- JPEG fallback -->
<img
src="photo-400w.jpg"
srcset="photo-400w.jpg 400w,
photo-800w.jpg 800w,
photo-1200w.jpg 1200w"
sizes="(min-width: 768px) 400px, 100vw"
alt="A landscape photo"
width="400" height="300"
>
</picture>
The window.devicePixelRatio property returns the current device pixel ratio as a floating-point number. This is useful for canvas rendering, dynamic image loading, and other scenarios where you need to know the DPR programmatically.
// Get current DPR
const dpr = window.devicePixelRatio;
console.log(`Device Pixel Ratio: ${dpr}`);
// React to DPR changes (e.g., window moved between displays)
const mediaQuery = window.matchMedia(
`(resolution: ${window.devicePixelRatio}dppx)`
);
mediaQuery.addEventListener('change', () => {
console.log(`DPR changed to: ${window.devicePixelRatio}`);
// Re-render canvas, reload images, etc.
});
DPR can change during a session in several scenarios. On desktop systems, dragging a browser window from a standard monitor to a Retina display (or vice versa) changes the DPR. Changing the OS display scaling setting also changes DPR. Using browser zoom changes the effective DPR because the browser adjusts the ratio of CSS pixels to hardware pixels. A 200% browser zoom on a DPR 1 display effectively creates a DPR of 2.
The HTML Canvas element is one area where DPR handling requires explicit attention. By default, a canvas has a 1:1 mapping between its internal pixel grid and CSS pixels. On a DPR 2 display, this means the canvas is internally rendering at half the hardware resolution, resulting in a blurry, pixelated appearance.
The fix is to scale the canvas's internal dimensions by the DPR while keeping its CSS display size unchanged.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1;
// Set CSS display size
const displayWidth = 400;
const displayHeight = 300;
canvas.style.width = displayWidth + 'px';
canvas.style.height = displayHeight + 'px';
// Set internal resolution to match hardware pixels
canvas.width = displayWidth * dpr;
canvas.height = displayHeight * dpr;
// Scale the context so drawing operations
// use CSS pixel coordinates
ctx.scale(dpr, dpr);
// Now draw as normal using CSS pixel values
ctx.fillRect(10, 10, 100, 50);
Without this scaling, lines, text, and shapes on the canvas appear blurry on Retina displays. With it, they render at full hardware resolution, producing crisp, sharp output. This technique is essential for data visualizations, charts, games, and any interactive canvas content.
Beyond images and canvas, CSS offers several tools for dealing with DPR.
You can target specific DPR values (or ranges) using the CSS resolution media feature.
/* Target 2x displays and above */
@media (min-resolution: 2dppx) {
.logo {
background-image: url('logo@2x.png');
background-size: 200px 50px;
}
}
/* Target 3x displays */
@media (min-resolution: 3dppx) {
.logo {
background-image: url('logo@3x.png');
background-size: 200px 50px;
}
}
For CSS background images, the image-set() function provides a cleaner syntax for serving resolution-appropriate images.
.hero {
background-image: image-set(
url('hero-1x.webp') 1x,
url('hero-2x.webp') 2x,
url('hero-3x.webp') 3x
);
}
The simplest solution for icons, logos, and illustrations is to use vector formats. SVG files render at any DPR without quality loss because they are defined mathematically rather than as a pixel grid. CSS features like border, box-shadow, and text rendering are inherently resolution-independent. Wherever possible, prefer SVG over PNG for interface elements. This eliminates the need for 2x and 3x variants entirely.
Serving high-DPR images has a direct cost: larger file sizes and increased bandwidth consumption. A 2x image has four times the pixel count of a 1x image, and a 3x image has nine times the pixels. Even with efficient compression, this translates to significantly larger files.
Research from various web performance teams has found that serving 2x images to 3x devices produces results that are visually indistinguishable from true 3x images in most cases, especially for photographic content. The perceptual difference between 2x and 3x is much smaller than between 1x and 2x. This suggests a practical strategy: serve 1x images to DPR 1 devices, 2x images to everything higher, and only serve 3x for specific use cases where the quality difference is perceptible (logos, icons with fine detail, text in images).
Format choice dramatically affects the file size impact of high-DPR images. WebP offers 25-35% smaller files than JPEG at equivalent quality. AVIF provides even better compression, often 40-50% smaller than JPEG. By combining high-DPR images with modern formats, you can serve sharp 2x images that are often smaller than 1x JPEGs.
<picture>
<source
type="image/avif"
srcset="photo-800w.avif 800w,
photo-1600w.avif 1600w"
sizes="(min-width: 768px) 800px, 100vw"
>
<source
type="image/webp"
srcset="photo-800w.webp 800w,
photo-1600w.webp 1600w"
sizes="(min-width: 768px) 800px, 100vw"
>
<img
src="photo-800w.jpg"
srcset="photo-800w.jpg 800w,
photo-1600w.jpg 1600w"
sizes="(min-width: 768px) 800px, 100vw"
alt="Photo" width="800" height="600"
loading="lazy" decoding="async"
>
</picture>
The loading="lazy" attribute (supported natively in all modern browsers) defers loading images until they are near the viewport. This is especially important for high-DPR images because deferring the load of large 2x or 3x images that are below the fold saves significant bandwidth on initial page load.
A common source of confusion is how DPR interacts with responsive design breakpoints. The key fact to remember is that CSS media queries use CSS pixels, not hardware pixels. This means DPR is already accounted for by the browser before your media queries evaluate.
An iPhone 15 Pro has 1179 hardware pixels across, but at DPR 3, its CSS viewport width is 393px. When your media query says @media (min-width: 768px), the iPhone evaluates it as false because 393 is less than 768. This is correct behavior, because the iPhone's screen is physically small and your tablet layout would not fit comfortably on it, regardless of how many hardware pixels it has.
This design means you generally do not need to worry about DPR when writing breakpoints. Your breakpoints respond to the effective layout width, which already accounts for pixel density. For more on choosing the right breakpoints, see our complete guide to responsive breakpoints and the CSS media queries guide.
The one area where DPR does intersect with responsive design is image selection. The sizes attribute in srcset should reflect the actual CSS width the image occupies at each breakpoint. Combined with the width descriptors, this lets the browser factor in both the layout width and the DPR to select the optimal image file.
Here are the key takeaways for handling DPR effectively in your web projects.
For testing your current device's DPR and viewport dimensions, the DisplayPixels screen size tool displays both values in real time.
Device Pixel Ratio is the ratio between physical hardware pixels and CSS (logical) pixels on a display. A DPR of 2 means each CSS pixel is rendered using a 2x2 grid of 4 hardware pixels. This makes text, icons, and images appear sharper on high-resolution displays like Apple Retina screens (DPR 2) or modern Android phones (DPR 2.5, 3, or higher).
Use window.devicePixelRatio to get the current DPR as a number. For example, on a Retina MacBook this returns 2, on an iPhone 14 Pro it returns 3. Note that this value can change during a session if the user moves the browser window between displays with different DPRs, or if they change their OS display scaling, so use matchMedia to listen for changes if needed.
Images look blurry on Retina displays when you serve a 1x resolution image that gets upscaled to fill the 2x (or higher) pixel grid. For example, a 200x200px image displayed in a 200x200 CSS pixel container on a 2x display is actually being stretched across 400x400 hardware pixels, causing visible blurriness. The fix is to serve a 400x400 source image using srcset, the picture element, or CSS image-set().
No. Serving 3x images to all devices wastes bandwidth and slows page loads for users on 1x or 2x displays. Use the srcset attribute or picture element to let the browser choose the appropriate image resolution based on the device's DPR and viewport size. The browser will download only the image it needs, optimizing both quality and performance.
CSS media queries use CSS pixels (logical pixels), not hardware pixels. A device with 1170 hardware pixels wide and a DPR of 3 reports a CSS viewport width of 390px. This means your breakpoints work consistently across devices regardless of DPR. A min-width: 768px media query triggers at the same effective layout width whether the device has 768, 1536, or 2304 hardware pixels across.