Developers search for one thing more than definitions: working code. You already know viewport and screen width aren’t the same—but when it’s 2 a.m. and you’re debugging why your canvas looks blurry on Retina or your <img> srcset isn’t switching, you need snippets that actually run.
Search volume for terms like “window.innerWidth vs screen.width” and “devicePixelRatio canvas” stays high because most articles explain the concepts and skip the implementation. This post fixes that: copy-paste JavaScript for screen.width, window.innerWidth, and devicePixelRatio (DPR), plus real use cases (responsive images and canvas scaling). No fluff, no “it depends”—just the code angle devs search for.
The Three Values Every Front-End Dev Should Know
Before the snippets, a 10-second mental model:
| API | What it is | Typical use |
|---|---|---|
| screen.width | Physical display width in CSS pixels (often the same as device width on mobile) | Device capability, analytics, "is this a phone?" |
| window.innerWidth | Width of the browser viewport in CSS pixels (scrollbar included) | Layout breakpoints, responsive CSS, "how much space do I have?" |
| window.devicePixelRatio | Ratio of physical pixels to CSS pixels | Sharp images, canvas resolution, "do I need @2x assets?" |
On a 1920×1080 monitor at 100% zoom, you might see screen.width === 1920 and innerWidth smaller if the window isn’t fullscreen.
On an iPhone 15 with a 393×852 logical viewport, innerWidth === 393 and devicePixelRatio === 3—so the physical pixel width is 393 × 3 = 1179.
Get these three in your head, then use the code below to detect them.
1. Detecting Screen Width (screen.width)
screen.width is the width of the user’s screen in CSS pixels. It usually doesn’t change when they resize the browser; it describes the display. Use it when you care about device class (e.g. phone vs desktop), not layout.
// Basic read
const screenWidth = window.screen.width;
console.log('Screen width (CSS px):', screenWidth);
// Optional: guard for SSR / non-browser
const screenWidthSafe = typeof window !== 'undefined' ? window.screen.width : 0;
When to use it: Analytics, feature flags (“show desktop-only feature”), or A/B tests by device size. Don’t use it for responsive layout—use viewport (innerWidth or media queries) instead.
2. Detecting Viewport Width (window.innerWidth)
window.innerWidth is the width of the browser viewport in CSS pixels, including the scrollbar. It changes when the user resizes the window. This is what you want for breakpoints and “how much horizontal space do I have?”
// Current viewport width
const viewportWidth = window.innerWidth;
console.log('Viewport width (CSS px):', viewportWidth);
// React to resize (e.g. for layout or logging)
function logViewport() {
console.log('Viewport:', window.innerWidth, 'x', window.innerHeight);
}
window.addEventListener('resize', logViewport);
// Don’t forget to removeListener when cleaning up (e.g. in useEffect return).
Getting layout width without scrollbar: If you need the “layout” width (what CSS sees in a media query), use a resize observer or match a media query in JS:
// Match a media query (same as CSS (min-width: 768px))
const isTabletOrLarger = window.matchMedia('(min-width: 768px)').matches;
const mediaQueryWidth = 768;
if (viewportWidth >= mediaQueryWidth) {
// Tablet/desktop layout
}
Use innerWidth (or media queries) for responsive layout, breakpoints, and conditional UI—not screen.width.
3. Detecting Device Device Pixel Ratio (DPR) (DPR)
devicePixelRatio is the ratio of physical pixels to CSS pixels. On a Retina Mac or modern phone it’s often 2 or 3; on a standard 1080p monitor it’s usually 1. You need this for crisp images and canvas.
// Basic read
const dpr = window.devicePixelRatio || 1;
console.log('DPR:', dpr);
// Typical buckets for responsive images
const density = dpr >= 3 ? '3x' : dpr >= 2 ? '2x' : '1x';
console.log('Asset density:', density);
Why || 1? Older or headless environments might not define devicePixelRatio; defaulting to 1 avoids NaN and keeps math safe.
Use Case 1: Responsive Images (srcset + sizes + DPR)
You want the right image for viewport size and pixel density: small viewport + high DPR (e.g. phone) gets a smaller logical size but high-res file; large viewport gets a wider image. Here’s the logic in JS so you can build URLs or pick sources yourself (e.g. for a React component or a CMS).
function getImageSuffix() {
if (typeof window === 'undefined') return '1x';
const dpr = Math.min(window.devicePixelRatio || 1, 3);
const w = window.innerWidth;
// Example breakpoints: mobile < 768, tablet < 1280, else desktop
const widthBucket = w < 768 ? 'sm' : w < 1280 ? 'md' : 'lg';
const dprSuffix = dpr >= 3 ? '@3x' : dpr >= 2 ? '@2x' : '';
return `${widthBucket}${dprSuffix}`;
}
// Use with your CDN or path: `/img/hero-${getImageSuffix()}.webp`
In HTML you’d typically use srcset and sizes and let the browser choose; the snippet above is the same logic in JS for when you control the URL (e.g. dynamic or component-driven images). Pair it with pixel density so you serve 2x/3x only where DPR justifies it.
Use Case 2: Canvas Scaling (Sharp on Retina)
Canvas has a drawing buffer size and a display size. If you set only the CSS size, the buffer is often 1:1 with CSS pixels, so on a 2x or 3x display the canvas looks soft. Scale the internal size by DPR, then use CSS to show it at the desired layout size.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1;
// Desired size in CSS pixels (e.g. match a container)
const cssWidth = 400;
const cssHeight = 300;
// Set display size (what user sees)
canvas.style.width = `${cssWidth}px`;
canvas.style.height = `${cssHeight}px`;
// Set buffer size (actual pixels: sharp on Retina)
canvas.width = cssWidth * dpr;
canvas.height = cssHeight * dpr;
ctx.scale(dpr, dpr);
// Now draw in CSS pixel coordinates (0..cssWidth, 0..cssHeight)
// The context scales everything up; the canvas stays sharp.
ctx.fillRect(10, 10, 100, 50);
After this, always draw in CSS pixel coordinates (0 to cssWidth, 0 to cssHeight). The context’s scale(dpr, dpr) handles the rest. Resize handling: on resize, recompute cssWidth/cssHeight (e.g. from getBoundingClientRect), set style and width/height again, then redraw.
One Snippet to Log All Three
Drop this in the console or a debug script to see the full picture at once:
function reportScreenViewportDPR() {
const screenW = window.screen?.width ?? 0;
const innerW = window.innerWidth ?? 0;
const dpr = window.devicePixelRatio ?? 1;
const physicalWidth = Math.round(innerW * dpr);
console.log({
'screen.width (CSS px)': screenW,
'window.innerWidth (CSS px)': innerW,
'devicePixelRatio': dpr,
'viewport physical width (px)': physicalWidth,
});
}
reportScreenViewportDPR();
window.addEventListener('resize', reportScreenViewportDPR);
Use this when debugging layout vs asset choices or when teaching the difference between viewport width and screen width.
Common Gotchas (So You Don’t Waste an Hour)
A few traps that bite even senior devs:
- Browser zoom changes everything. At 150% zoom,
window.innerWidthdrops anddevicePixelRatiocan change in some browsers. Test at 100% and at 125%/150% if your app is zoom-sensitive. - screen.width can “lie” on multi-monitor. It usually reports the primary screen; on Linux or exotic setups you may get the wrong monitor. Prefer viewport (innerWidth) for layout.
- SSR and Node have no window. Any snippet that touches
windoworscreenmust run in the browser or be guarded withtypeof window !== 'undefined'(or run only inuseEffect/onMounted). - Canvas: set width/height in pixels, not style. The buffer size is
canvas.widthandcanvas.height(numbers); the display size iscanvas.style.widthandstyle.height(strings with units). Mix them up and you get stretch or blur.
Get these right once and your responsive images and canvas code stay predictable across devices.
Quick Reference: What to Use When
- Responsive layout / breakpoints →
window.innerWidthor CSS media queries. - “Is this a small device?” →
screen.width(or innerWidth) with a threshold. - Responsive images (size + density) →
innerWidth(or sizes) +devicePixelRatio. - Canvas sharp on Retina → Set canvas width/height to
cssSize * devicePixelRatio, thenctx.scale(dpr, dpr)and draw in CSS coordinates. - Analytics / device class →
screen.width(and optionally DPR) is fine; prefer viewport for layout-related metrics.
Wrap-Up
Viewport width, screen width, and DPR each answer a different question. Use screen.width for device capability, window.innerWidth for layout and breakpoints, and devicePixelRatio for resolution-aware assets and canvas. The snippets above are the code angle devs search for—drop them into your project, adapt the thresholds to your breakpoints, and you’ll have responsive images and sharp canvas without the guesswork.
For a live readout of your current screen and viewport, use our free screen size tool; for more on how resolution and density affect design, see how screen size impacts web design and UX.
Related Articles
Continue reading with these related posts
How to Build a Responsive Site That Passes Screen Size Tests
A step-by-step audit for responsive sites: pick viewports with Compare Devices, test with DevTools and real devices, implement min-width/max-width/orientation media queries—extends UX without repeating best practices.
Screen Resolution vs Screen Size vs Pixel Density (PPI vs DPI Explained)
Confused about screen resolution, screen size, and pixel density? Learn the differences between PPI vs DPI, see real-world examples (iPhone 15 vs Galaxy S24), and discover how to calculate pixel density.

How Screen Size Impacts Web Design & UX: Best Practices Explained
Learn how screen size affects web design and user experience. Discover best practices for responsive layouts and improving engagement across devices.
