From window.screen to devicePixelRatio: A Complete Guide to Browser Screen APIs
From window.screen to devicePixelRatio: A Complete Guide to Browser Screen APIs#
While building a responsive layout debugger, I dove deep into browser screen APIs. Beyond the common screen.width, there’s a lot more to explore. Here’s what I learned.
Core API: The screen Object#
The window.screen object provides rich screen information:
interface ScreenInfo {
width: number // Physical screen width (pixels)
height: number // Physical screen height (pixels)
availWidth: number // Available width (minus taskbar)
availHeight: number // Available height (minus taskbar)
colorDepth: number // Color depth (usually 24 or 32-bit)
pixelDepth: number // Pixel depth (usually equals colorDepth)
orientation: string // Screen orientation (landscape-primary, etc.)
}
Get current screen info:
const screenInfo = {
width: window.screen.width,
height: window.screen.height,
availWidth: window.screen.availWidth,
availHeight: window.screen.availHeight,
colorDepth: window.screen.colorDepth,
orientation: window.screen.orientation?.type || 'unknown'
}
console.log(screenInfo)
// { width: 1920, height: 1080, availWidth: 1920, availHeight: 1040, colorDepth: 24 }
Note: In multi-monitor setups, screen.width returns the primary monitor resolution. If your window is on a secondary monitor, these values may be inaccurate.
Device Pixel Ratio: devicePixelRatio Matters#
With Retina displays and high-DPI monitors, CSS pixels and physical pixels are no longer 1:1. devicePixelRatio is that ratio:
const dpr = window.devicePixelRatio
// Regular screen: 1
// Retina display: 2 or 3
// 4K monitor: might be 1.5 or 2
// Calculate Canvas real resolution
const canvas = document.getElementById('myCanvas')
const rect = canvas.getBoundingClientRect()
// Set Canvas physical resolution
canvas.width = rect.width * dpr
canvas.height = rect.height * dpr
// Scale context to match CSS pixels
const ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr)
This ratio directly affects Canvas clarity. Without handling devicePixelRatio, Canvas looks blurry on high-DPI screens.
Window Dimensions: innerHeight vs outerHeight#
Browser windows have two sets of dimensions:
// Window outer dimensions (includes title bar, borders)
window.outerWidth // Entire browser window width
window.outerHeight // Entire browser window height
// Window inner dimensions (viewport size)
window.innerWidth // Viewport width (includes scrollbar)
window.innerHeight // Viewport height (includes scrollbar)
// Document dimensions (actual page size)
document.documentElement.scrollWidth
document.documentElement.scrollHeight
The differences:
| Property | Meaning | Typical Value (1920×1080 screen) |
|---|---|---|
outerHeight |
Total browser window height | 1040px |
innerHeight |
Viewport height (with scrollbar) | 900px |
scrollHeight |
Full document height | Can be large |
Screen Orientation Detection: The orientation API#
Mobile development requires detecting portrait/landscape:
// Get current orientation
const orientation = window.screen.orientation?.type
// Possible values:
// - 'portrait-primary'
// - 'portrait-secondary' (upside down)
// - 'landscape-primary'
// - 'landscape-secondary' (upside down)
// Listen for orientation changes
window.screen.orientation?.addEventListener('change', (e) => {
console.log('Screen orientation changed:', e.target.type)
})
// Traditional method (better compatibility)
window.addEventListener('orientationchange', () => {
console.log('Orientation:', window.orientation) // 0, 90, -90, 180
})
Touch Screen Detection#
Detect if a device supports touch:
const touchSupport = {
// Method 1: Check events
hasTouch: 'ontouchstart' in window,
// Method 2: Check touch points
maxTouchPoints: navigator.maxTouchPoints || 0,
// Method 3: CSS media query
isTouchDevice: window.matchMedia('(hover: none) and (pointer: coarse)').matches
}
console.log(touchSupport)
// PC: { hasTouch: false, maxTouchPoints: 0, isTouchDevice: false }
// iPad: { hasTouch: true, maxTouchPoints: 5, isTouchDevice: true }
Real-time Window Change Monitoring#
Building responsive tools requires real-time updates:
function useScreenInfo() {
const [info, setInfo] = useState({
width: window.innerWidth,
height: window.innerHeight,
dpr: window.devicePixelRatio
})
useEffect(() => {
const updateInfo = () => {
setInfo({
width: window.innerWidth,
height: window.innerHeight,
dpr: window.devicePixelRatio
})
}
window.addEventListener('resize', updateInfo)
return () => window.removeEventListener('resize', updateInfo)
}, [])
return info
}
Practical Use Cases#
1. Responsive Breakpoint Detection#
function getCurrentBreakpoint() {
const width = window.innerWidth
if (width < 640) return 'xs' // Mobile
if (width < 768) return 'sm' // Large mobile
if (width < 1024) return 'md' // Tablet
if (width < 1280) return 'lg' // Small laptop
if (width < 1536) return 'xl' // Desktop
return '2xl' // Large screen
}
2. HiDPI Canvas Rendering#
function setupHiDPICanvas(canvas) {
const dpr = window.devicePixelRatio || 1
const rect = canvas.getBoundingClientRect()
// Set physical resolution
canvas.width = rect.width * dpr
canvas.height = rect.height * dpr
// CSS size stays the same
canvas.style.width = `${rect.width}px`
canvas.style.height = `${rect.height}px`
// Scale context
const ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr)
return ctx
}
3. Adaptive Layout#
// Adjust toolbar based on viewport height
function adjustToolbar() {
const vh = window.innerHeight
if (vh < 600) {
// Small screen: compact toolbar
toolbar.classList.add('compact')
} else {
// Large screen: expanded toolbar
toolbar.classList.remove('compact')
}
}
Caveats#
1. Privacy Restrictions#
For privacy, some browsers limit returned information:
// Firefox privacy mode
window.screen.width // Might return 0 or inaccurate value
// Some browsers round to nearest 100
window.screen.width // Actual 1920, returns 1900
2. Async Access#
Some info (like orientation) might need async access:
if (screen.orientation) {
screen.orientation.addEventListener('change', () => {
console.log('Orientation changed')
})
}
3. Mobile Device Quirks#
Mobile devices return logical resolution, not physical:
// iPhone 12
screen.width // 390 (logical resolution)
screen.height // 844 (logical resolution)
// Physical resolution needs calculation
const physicalWidth = screen.width * devicePixelRatio
const physicalHeight = screen.height * devicePixelRatio
// 1170 × 2532
Summary#
Browser screen APIs may seem simple, but combining them enables powerful features:
- Responsive debugging: Real-time viewport size and breakpoint display
- HiDPI Canvas rendering: Adjust resolution based on devicePixelRatio
- Device detection: Touch screen, orientation, available space
- Layout optimization: Auto-adjust interface based on viewport height
Based on these APIs, I built an online tool: Screen Info Detector, showing all screen parameters in real-time for frontend developers debugging responsive layouts.
Related: Responsive Test Tool | Percentage Calculator