Physical Pixels vs Logical Pixels: Interactive Guide with Your Screen's Real Numbers
Your screen — live detection:
You set your monitor to 3840×2160, but screen.width in JavaScript says 2560 (and screen.height says 1440). You take a screenshot — 3840 pixels wide. You write width: 100px in CSS and it renders as 200 physical pixels. What is going on?
Your screen actually runs two resolution systems — physical pixels (real hardware dots) and logical pixels (what software uses for layout). The ratio between them is the Device Pixel Ratio (DPR), and it affects every single coordinate on your screen. Your real numbers are above.
Open Free Screen Coordinates ToolYour Screen's Numbers — Live
Before diving into theory, here are your screen's actual values right now:
These values come from your browser's actual APIs — no guessing. The "estimated" physical resolution is calculated as screen.width × DPR and screen.height × DPR; it matches the real hardware in most cases but can be affected by GPU virtual super-resolution or browser zoom. If DPR is 1.0, your physical and logical pixels are identical. If it is higher, there is a transformation happening between what software sees and what your screen displays. Use our screen coordinates tool to see how this affects mouse positions in real time.
What Are Physical Pixels?
A physical pixel (also called a device pixel) is a single, real dot on your screen hardware. It is the smallest addressable element of your display. On an LCD panel, each physical pixel is made up of three sub-pixels (red, green, blue), and together they produce one color dot.
Your monitor's physical resolution tells you exactly how many of these dots it has:
- A 1920×1080 monitor has 2,073,600 physical pixels
- A 3840×2160 (4K) monitor has 8,294,400 physical pixels
- An iPhone 15 Pro has 2,556×1,179 physical pixels in a 6.1-inch screen
Physical pixels never change for a given display. A 4K monitor always has 3840×2160 physical pixels regardless of your Windows scaling settings. The hardware is fixed.
For a comparison of what different physical pixel counts mean for coordinate systems, see our Screen Resolution Comparison guide.
What Are Logical Pixels (CSS Pixels)?
A logical pixel (also called a CSS pixel, device-independent pixel (DIP), or point on macOS) is a unit of measurement that software uses for layout. It is an abstraction — a logical pixel is not necessarily one physical pixel.
On a standard 1080p monitor at 100% scaling, one logical pixel = one physical pixel. Simple. But on a Retina MacBook Pro with DPR 2, one logical pixel = a 2×2 grid of physical pixels (4 physical pixels total). On a Windows 4K display at 150% scaling, one logical pixel = a 1.5×1.5 area of physical pixels.
Why logical pixels exist: Without them, a button set to 100×30 pixels would be tiny on a 4K phone screen (where pixels are microscopic) but huge on a 720p projector. Logical pixels let developers write width: 100px and have it appear at a similar physical size on every device, regardless of pixel density.
Visual comparison — each colored square is one physical pixel. One logical pixel maps to different grids depending on DPR:
DPR 1 (1 CSS px = 1×1)
DPR 1.5 (1 CSS px = 1.5×1.5)
DPR 2 (1 CSS px = 2×2)
DPR 3 (1 CSS px = 3×3)
Device Pixel Ratio: The Bridge Between Physical and Logical
The Device Pixel Ratio (DPR) is the multiplier that converts between logical and physical pixels:
physical_pixels = logical_pixels × DPR
Examples (width only):
1920 logical × DPR 1.0 = 1920 physical (standard 1080p)
2560 logical × DPR 1.5 = 3840 physical (4K at 150% scaling)
1440 logical × DPR 2.0 = 2880 physical (MacBook Retina)
In JavaScript, you can read your DPR with window.devicePixelRatio. This value is read-only — it is determined by your display hardware and OS scaling settings.
DPR Is Not Always an Integer
Windows commonly uses fractional DPR values: 1.25 (125%), 1.5 (150%), 1.75 (175%). macOS uses exactly 2.0 for Retina displays. Android devices use various values (1.5, 2.0, 2.625, 3.0, 3.5, 4.0). Fractional DPR means that logical pixels do not map cleanly to physical pixels — one logical pixel might cover parts of multiple physical pixels, which is why text rendering on Windows at 125% scaling can look slightly blurry.
For how DPR interacts with DPI scaling on Windows and breaks automation scripts, see our DPI Scaling & Coordinates guide.
DPR by Device: MacBook, Windows, Android, iPhone
Common devices and their DPR values:
| Device | Physical Resolution | Logical Resolution | DPR | 1 CSS Pixel = |
|---|---|---|---|---|
| Standard PC monitor (1080p) | 1920×1080 | 1920×1080 | 1.0 | 1 physical pixel |
| Windows 4K at 150% | 3840×2160 | 2560×1440 | 1.5 | 2.25 physical pixels |
| Windows 4K at 200% | 3840×2160 | 1920×1080 | 2.0 | 4 physical pixels |
| MacBook Pro 14" | 3024×1964 | 1512×982 | 2.0 | 4 physical pixels |
| MacBook Pro 16" | 3456×2234 | 1728×1117 | 2.0 | 4 physical pixels |
| iPad Pro 11" | 2388×1668 | 1194×834 | 2.0 | 4 physical pixels |
| iPhone 15 Pro | 2556×1179 | 393×852 | 3.0 | 9 physical pixels |
| Pixel 8 | 2400×1080 | 412×915 | ~2.625 | ~6.9 physical pixels |
| Samsung Galaxy S24 | 2340×1080 | 360×780 | ~3.0 | 9 physical pixels |
Notice the pattern: Apple sticks to integer DPR (2 or 3). Windows uses fractional values (1.25, 1.5, 1.75) for finer scaling control. Modern apps and browsers handle fractional DPR cleanly with sub-pixel rendering — only legacy, non-DPI-aware applications get bitmap-stretched and look blurry. Android varies by manufacturer.
What This Means for Screen Coordinates and Automation
So what does this mean in practice?
- Automation tools disagree on coordinates. PyAutoGUI without DPI awareness uses logical coordinates; the Windows API
GetCursorPosreturns physical ones (for DPI-aware processes). Mix them up and every position is off by the DPR factor. Our PyAutoGUI Coordinates guide has the fix. - Screenshots capture physical pixels. On a 4K display at 150% scaling, a screenshot is 3840×2160 — not 2560×1440. Trying to locate a UI element by its logical coordinates in that screenshot? Multiply by DPR first.
- CSS coordinates are always logical. Set
left: 100px; top: 200pxand those are logical pixels — the browser converts them to physical pixels behind the scenes. That is whygetBoundingClientRect()returns CSS pixels. - Multi-monitor setups can have mixed DPR. A Retina laptop screen (DPR 2) next to a standard external monitor (DPR 1) means the same coordinate maps to different physical spots on each display. Our Multi-Monitor Coordinates guide covers this.
Quick Reference: Which Coordinate System Am I Using?
| Tool / API | Coordinate Type | Resolution Reported |
|---|---|---|
| PyAutoGUI (default) | Logical | Logical (e.g., 2560×1440) |
| PyAutoGUI (with SetProcessDPIAware) | Physical | Physical (e.g., 3840×2160) |
| AutoHotkey A_ScreenWidth | Logical | Logical |
| Windows GetCursorPos (DPI-aware) | Physical | Physical |
| JavaScript screen.width/height | Logical (CSS) | Logical |
| JavaScript window.innerWidth | Logical (CSS) | Logical |
| CSS getBoundingClientRect() | Logical (CSS) | N/A |
| macOS NSScreen (Quartz) | Points (logical) | Points |
Frequently Asked Questions
Is DPR the same as DPI?
Related but different. DPI (dots per inch) measures physical pixel density — how many pixels fit in one inch of screen. DPR (device pixel ratio) is the ratio of physical to logical pixels. A high DPI screen may have a DPR of 1 if the OS does not scale it. DPR is about the software mapping; DPI is about the hardware density.
Why does my Retina Mac look sharper than my 4K Windows PC?
macOS uses integer DPR (2.0), which means every CSS pixel maps to exactly a 2×2 grid of physical pixels — a clean 4:1 mapping. Windows commonly uses fractional DPR (1.25, 1.5, 1.75), which means a CSS pixel maps to a non-integer number of physical pixels. This causes sub-pixel rendering artifacts and slight blurriness in non-DPI-aware applications.
Can I change my DPR?
You change it indirectly through your OS scaling settings. On Windows: Settings → System → Display → Scale & layout. On macOS: System Settings → Displays → choose "Default" for native DPR or "Scaled" for a different logical resolution. On Android: Settings → Display → Display size / Font size (limited control). The DPR changes instantly, but some applications need to be restarted to pick up the change.
Why does window.devicePixelRatio change between monitors?
If you drag your browser from a DPR 1.0 external monitor to a DPR 2.0 Retina laptop screen, window.devicePixelRatio updates to reflect the new monitor's DPR. You can listen for this with the matchMedia('(resolution: ' + dpr + 'dppx)') change event. This is relevant for web applications that need to handle mixed-DPI setups.