Home Browser & Device Tools Guide

Pixels, viewports, and device pixel ratio: what each one actually measures

Four numbers describe your display, all called some flavour of "pixel" — and they can disagree by a factor of three. Here's what each one actually means.

A designer hands over a 2880×1800 mockup. The developer asks: is that physical or logical? Awkward silence. Or another version of the same scene: an icon looks crisp on the designer's laptop and noticeably blurry on the QA tester's Windows machine, and nobody can quite agree on whose fault that is. The answer to both is the same answer, and it sits in the gap between four numbers that all get called "pixels" in casual conversation.

The four numbers are: physical pixels, CSS pixels, device pixel ratio, and the viewport. They describe different things, they're allowed to disagree, and the gap between them can be a factor of three. Knowing which is which is the only way to ship images that stay sharp and layouts that behave at every breakpoint.

Physical pixels — what the panel actually has

The literal dots on the screen. A 14-inch MacBook Pro has roughly 3024×1964 physical pixels. A 27-inch 1080p monitor has 1920×1080. The OS knows this number; almost no application code does. Web pages don't see it directly, and most of the time you don't need it — it's the raw resolution of the hardware, not the resolution your CSS works in.

Marketing tends to lead with this number ("5K display", "4K monitor") because it sounds biggest. Designers tend to think in this number because it's what their files are saved in. Developers, by contrast, almost never deal with it directly — the browser hides it.

CSS pixels — what your code measures in

The browser exposes a logical pixel grid that's designed to be roughly the same physical size on every display. A width: 320px element is about the same physical width on a phone and on a 4K monitor — slightly larger on the phone, in fact, because phones are held closer to the eye. The browser fakes this by drawing one CSS pixel as two or three physical pixels on high-density screens.

CSS pixels are what every px in your stylesheet refers to. Media queries (@media (max-width: 768px)) measure CSS pixels. JavaScript properties like element.offsetWidth return CSS pixels. Unless you're doing something unusual with a canvas or WebGL, you'll spend your entire career in CSS pixels and never think about the physical ones.

Device pixel ratio (DPR) — the bridge

DPR is the multiplier between the two. physical pixels per CSS pixel. Most standard desktop monitors are DPR 1: one CSS pixel equals one physical pixel. Retina laptops and modern phones are DPR 2: a single CSS pixel is drawn as a 2×2 block of physical pixels. A few high-end Android phones go to DPR 3 — nine physical pixels per CSS pixel.

DPR can also be fractional. Plenty of Windows laptops run at 125% or 150% OS display scaling, which shows up to the browser as DPR 1.25 or 1.5. window.devicePixelRatio in JavaScript returns the current value — and it can change at runtime if you drag the browser window between two monitors with different scaling settings.

Viewport vs screen vs window

Three more numbers, all measuring something slightly different:

  • Screen. The whole display, including the OS taskbar, dock, menu bar, and any system chrome. screen.width and screen.height in JavaScript.
  • Window. The browser's outer frame, including the title bar and any docked developer tools panel. Almost never the number you want.
  • Viewport. The visible area inside the window where the page actually renders. CSS media queries measure this. 100vw equals the full viewport width. window.innerWidth returns it in JavaScript.

The screen rarely matches the window which rarely matches the viewport. Mobile browsers add extra complications: a separate visual viewport (what's currently on screen, factoring in pinch zoom) vs layout viewport (what the page was laid out against), and the on-screen keyboard pushes the visual viewport up without changing the layout one. Most of the time the layout viewport is the one your CSS cares about.

Why this matters for responsive design and image assets

Two practical places these numbers bite.

Image assets. An icon authored at 100×100 looks crisp on a DPR-1 monitor but blurry on a DPR-2 laptop, because the browser is stretching 100 physical pixels of source over 200 physical pixels of output. The fix is srcset:

<img src="icon-1x.png" srcset="icon-1x.png 1x, icon-2x.png 2x, icon-3x.png 3x">

The browser picks the right asset for the current DPR. Modern build pipelines automate this; if yours doesn't, you're shipping blurry images to half your users.

Responsive breakpoints. A @media (max-width: 768px) rule triggers at the same CSS-pixel width on a phone and an iPad. That's deliberate — the iPad's higher physical resolution doesn't push it into the desktop layout. If you were measuring physical pixels, every retina device would get the desktop layout regardless of physical size; the whole responsive-design pattern would fall apart.

A worked example: the same div on three devices

Imagine a single CSS rule: .card { width: 320px; height: 180px; }. Here's what that produces on three real devices:

  • Old desktop monitor (DPR 1, 1920×1080 physical). The card occupies 320×180 physical pixels. About 1/6 of the screen width. Sharp by default — nothing to scale.
  • 14-inch MacBook (DPR 2, 1512×982 CSS / 3024×1964 physical). The card occupies 320×180 CSS pixels — about 1/5 of the screen width. Internally the browser draws it as 640×360 physical pixels, so a 1px border is drawn as 2 physical pixels wide. Still sharp, because the rendering pipeline scales vector content properly.
  • Pixel 8 phone (DPR ~2.75, 412×915 CSS / 1080×2400 physical). The card occupies 320×180 CSS pixels — about 78% of the screen width. Internally drawn as 880×495 physical pixels. The border is drawn at 2.75 physical pixels, which the browser snaps to either 2 or 3 — visible on close inspection but unnoticeable in normal use.

Same CSS rule, three different physical sizes, consistent visual size relative to the screen. That's the system working as intended.

Common pitfalls

A few specific gotchas worth knowing:

  • Canvas drawing. An HTML canvas set to width="400" via the attribute has 400 backing pixels, regardless of DPR. On a DPR-2 screen, drawing into it at CSS-pixel coordinates produces blurry output unless you explicitly multiply the backing size by DPR and scale the context.
  • Hairline borders. A 1px CSS border on a DPR-1 screen is one physical pixel — as thin as the hardware allows. On DPR-2 it's two physical pixels, which looks thicker than the designer intended. The fix is border-width: 0.5px on retina, which the browser can render as one physical pixel.
  • Background images. background-image: url(...) doesn't have srcset. Use image-set() instead, or you'll ship the same image at every DPR.

When to use the screen resolution checker

The screen resolution checker on this site shows all four numbers at once and updates the viewport values live as you resize the window. It's the fastest way to confirm what your CSS and JavaScript are actually seeing, especially when a layout looks fine on your machine and broken on someone else's.

Related reading

The browser identity tool covers the rest of the picture — name, version, platform. The browser diagnostic produces the full single-page report. And the user-agent vs Client Hints guide covers how the browser exposes its platform info — the underlying mechanism for the headers that responsive-design servers used to rely on before viewport-based design took over.