Skip to content
ScreenMetricLab

Cookie settings

Manage your preferences

Essential features

Required for security, page delivery, and remembering this privacy choice.

Always on

Advertising

ScreenMetricLab does not currently serve ads. Advertising consent controls will be added before ads are enabled.

Not in use

Practical guide

Device Pixel Ratio Explained

Understand DPR and why high-DPI screens affect CSS pixels, screenshots, and image assets.

Updated 2026-09-05 Reviewed by ScreenMetricLab Editorial Team 5 min read

What DPR means

Device pixel ratio is the relationship between CSS pixels and physical display pixels. A DPR of 2 means one CSS pixel can be represented by roughly two physical pixels in each direction, which is common on many high-DPI screens.

Why DPR matters for images

Images that look sharp at DPR 1 can appear soft on high-DPI displays if only one low-resolution asset is served. Responsive images, srcset, and 2x or 3x image assets help browsers choose sharper files when needed.

Why fractional DPR values happen

Values such as 1.25 or 1.5 are common on desktop systems with display scaling or browser zoom. JavaScript cannot always separate browser zoom from OS scaling, so the result should be treated as the effective browser/device scaling context.

How to use DPR in QA

Include DPR when reporting screenshots, blurry icons, canvas rendering issues, or layout differences across devices. It helps explain why a high-resolution display can still have a smaller CSS viewport width.

DPR examples

DPR values are browser-reported scaling context. Treat them together with viewport width instead of using them alone.

DPR 1

One CSS pixel maps closely to one physical pixel.

DPR 2

High-DPI screens may need 2x images for sharp assets.

DPR 1.25 / 1.5

Often appears with OS display scaling or browser zoom.

Run a canvas and responsive-image example

Save this complete example as an HTML file and open it in a browser. The canvas keeps a 120 × 120 CSS-pixel box while its backing bitmap follows DPR. The image uses generated 1x, 2x, and 3x PNG candidates, so no external image files are required. Change page zoom, then press Update; the browser chooses the image candidate and may reuse a cached larger candidate.

<!doctype html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DPR canvas and image test</title>
<canvas id="sample" style="width:120px;height:120px" aria-label="Canvas density sample"></canvas>
<img id="photo" width="120" height="120" alt="Generated responsive-image density sample">
<button id="update" type="button">Update</button>
<pre id="readings"></pre>
<script>
const canvas = document.querySelector('#sample');
const image = document.querySelector('#photo');
function paint(target, density) {
  target.width = target.height = Math.round(120 * density);
  const ctx = target.getContext('2d');
  ctx.setTransform(target.width / 120, 0, 0, target.height / 120, 0, 0);
  ctx.fillStyle = '#e0f2fe';
  ctx.fillRect(0, 0, 120, 120);
  ctx.fillStyle = '#0f172a';
  ctx.font = '16px sans-serif';
  ctx.fillText(`${density}x bitmap`, 8, 62);
}
const candidates = [1, 2, 3].map(density => {
  const bitmap = document.createElement('canvas');
  paint(bitmap, density);
  return { url: bitmap.toDataURL('image/png'), density };
});
image.srcset = candidates.map(item => `${item.url} ${item.density}x`).join(', ');
image.src = candidates[0].url;
function update() {
  const dpr = window.devicePixelRatio || 1;
  paint(canvas, dpr);
  document.querySelector('#readings').textContent = JSON.stringify({
    dpr, cssWidth: canvas.getBoundingClientRect().width,
    bitmapWidth: canvas.width, viewportWidth: window.innerWidth,
    visualScale: window.visualViewport?.scale ?? null,
    selectedImageDensity: candidates.find(item => item.url === image.currentSrc)?.density ?? null
  }, null, 2);
}
document.querySelector('#update').addEventListener('click', update);
image.addEventListener('load', update);
window.addEventListener('resize', update);
window.visualViewport?.addEventListener('resize', update);
update();
</script>

At DPR 2, expect a 240 × 240 backing bitmap inside the unchanged 120 × 120 CSS box. For production photos, export separate raster files at those densities and use the same srcset pattern. Page zoom can change DPR; pinch zoom changes visual scale without changing DPR. This test reports browser behavior, not a measurement of panel PPI.

Sources, checked September 5, 2026: MDN devicePixelRatio and zoom behavior; MDN responsive-image density candidates.

Frequently asked questions

Is higher DPR always better?

A higher DPR can make text and graphics sharper, but it also means larger image assets may be needed for best quality.

Why is my DPR 1.25?

Fractional values usually come from browser zoom, OS display scaling, or device-specific display behavior.

Does DPR change CSS breakpoints?

Breakpoints usually use CSS viewport width, but DPR affects how physical pixels map to CSS pixels.

Can DPR change while zooming?

Page zoom changes the effective DPR. Pinch zoom magnifies the visual viewport without changing DPR. Record devicePixelRatio and visualViewport.scale together; neither reading alone identifies the hardware density.