CSS Pixels vs Device Pixels: Why "It Looks Fine on My Monitor" Is a Bug Report
Most layout bugs are not bugs. They're mismatches between the viewport we designed on and the viewport someone else is using.
Here's the thing that trips people up: a phone can report a 412 CSS-pixel-wide screen while being physically half the size of your laptop, and a 4K monitor at 200% scaling gives you exactly the same usable width as a 1080p one. Resolution and viewport are not the same number, and treating them as one is where "it works on my machine" comes from.
Three numbers that get confused
| Number | What it really means | Where you see it |
|---|---|---|
| Physical resolution | Actual pixel count of the panel, e.g. 3840×2160 | Product specs, OS display settings |
| CSS viewport width | What window.innerWidth reports after scaling and zoom | DevTools device mode, media queries |
| Device pixel ratio | Physical pixels per CSS pixel (1, 1.25, 1.5, 2, 3) | window.devicePixelRatio |
A 27" 1440p monitor at 100% gives you roughly 2560 CSS pixels to play with. A 15" laptop at 1920×1080 and 150% scaling gets 1280. A common Android phone gets somewhere around 360–412. Those are three wildly different layouts, and none of them tell you how big the screen physically is.
Why 1920 already equals 4K
Once you account for scaling, a 4K panel at 200% has a 1920×1080 CSS viewport — the same layout budget as a plain 1080p screen. So "we tested on 4K" is not a wider test than "we tested on 1080p". If you want the wide end of the curve you need an ultrawide (3440 or 5120 physical) or a monitor at 100% scaling.
// Print the real numbers of whatever device you're on console.log({ cssWidth: window.innerWidth, cssHeight: window.innerHeight, dpr: window.devicePixelRatio, physicalWidth: window.innerWidth * window.devicePixelRatio, }); Run that on a phone, a laptop and your desk monitor. The spread in cssWidth is usually much smaller than people expect, and the spread in physical size is much larger.
The five profiles that catch the most layout problems
- 1366×768 — still common in offices, education and cheap laptops. Catches overflowing navs and fixed-height hero sections.
- 1920×1080 at 125–150% scaling — the "high-DPI laptop": effectively 1280–1536 CSS px.
- 2560×1440 at 100% — the desktop default; the width most designs are actually drawn for.
- 3440×1440 ultrawide — catches max-width-less layouts stretching into unreadable line lengths.
- 390×844 (phone) — plus one small Android around 360 px, which is stricter than the iPhone.
That's five checkpoints instead of infinite combinations, and it covers the four scaling regimes plus both extremes of width.
Turning it into a repeatable check
Manual resizing is a good start, but the useful version is deliberate and repeatable:
- Fix the profile list in the project, not in someone's head, so every release is measured the same way.
- Record the viewport next to every screenshot in bug reports. A screenshot without a viewport is only half a bug.
- Compare across profiles: if a heading wraps differently on two screens, that's a layout rule, not a mystery.
- Watch device pixel ratio when testing text and icons: at DPR 1.5 and 2, hairline borders and 1px icons start to disappear.
If you just need the raw numbers while deciding on a target, Screen Size Comparison compares screen sizes and resolutions side by side — useful for sanity-checking what CSS width a given physical panel will actually give you.
The takeaway
Resolution is a spec sheet number. The viewport is what your CSS sees. Design and test against the viewport, pick five profiles that span the real world, and write the viewport down next to every screenshot — the "works on my monitor" class of bugs mostly disappears on its own.