Testing Responsive CSS Designs with Browser DevTools and Automated Checks

Test responsive CSS designs that use container queries, viewport units, and user preference queries using browser DevTools and automated checks.

Testing Responsive CSS Designs: from Viewport Only to Container Plus Viewport

You cannot test a modern responsive layout the way you tested one in 2019. The old method, resize the browser window, check the media query breakpoints, repeat, still works for viewport-level layout, but it misses half of what your CSS is doing now. Container queries respond to the size of a parent, not the viewport. Viewport units like dvh, svh, and lvh respond to the dynamic chrome, which DevTools does not simulate. User preference media queries respond to OS settings that device mode ignores. Testing responsive CSS designs systematically means learning which tool answers which question, and accepting that no single tool answers all of them.

Start With Device Mode, Then Go Further

Start with Chrome DevTools device mode for viewport breakpoints. Add the container query inspector for component-level breakpoints. Switch to a real mobile device for dynamic viewport units. Then run the @supports checks and Interop dashboard lookups to know what your target engines actually support. Each section names the failure mode you are guarding against and the technique that catches it.

Browser DevTools Responsive Testing CSS: What Device Mode Can and Cannot Do

Chrome DevTools device mode is the fastest way to test viewport media queries. Open DevTools, toggle device mode, and you get a responsive viewport mode that lets you drag the edge of the emulated screen through every width from the narrowest phone to a wide desktop. This is where you test your @media breakpoints: the point where the header collapses, where the grid goes from four columns to two, where the navigation turns into a hamburger.

What Device Mode Misses

But device mode has a hard limit. It emulates the viewport, not the containers inside it. If your card grid uses a @container query based on the width of a sidebar wrapper, resizing the device viewport changes that sidebar width only if the sidebar itself is sized in viewport units. If the sidebar is sized in percentage of a grid track, the viewport resize may not change it at all. The container query breakpoints sit invisible to device mode.

What Device Mode Does Well

Device mode handles continuous resize testing across the full width range, device pixel ratio testing at 1x, 2x, and 3x scaling, and the Lighthouse responsive audit. The Lighthouse responsive audit checks for viewport meta tag issues, tap target sizes, and fixed-width content, all viewport-level concerns. Run it from the Audits panel. Do not stop there.

Drag continuously. The most common mobile viewport widths cluster around 360px to 414px, but your layout has to survive every width in between. Do not jump from a phone width to a tablet width and declare victory. A breakpoint you never test will fire on real devices, and you will ship a layout that pins content against the edge.

Container Query Testing Technique: Resize the Container, Not the Viewport

Container queries change what you resize during a test. A container query fires when the container crosses its threshold, regardless of what the viewport is doing. To test it, you need to change the container’s width directly.

Using the Container Query Inspector

The simplest technique: in the DevTools Elements panel, select the container, switch to the layout tab, and edit the inline width. Change it and watch the container query styles apply. That works, but it is clumsy for repeated testing. The container query inspector is better.

Chrome DevTools added a container query inspector in the same release that shipped size container queries. When you select an element inside a container, the Styles pane shows a container badge. Click it, and the inspector highlights the container and shows a dotted line at each container query breakpoint. From there you can drag the container’s edges directly in the rendered page, just like dragging the viewport edge in device mode.

Select the container, not the viewport, and drag the container’s own width boundary. You are testing whether the component reflows correctly as its parent shrinks and grows, independent of the page chrome.

Testing the Fallback Path

What if you support engines without container queries? Write a fallback using @media breakpoints or viewport-relative units. Test the fallback in device mode. Then test the container query version in the container inspector. Both sets of styles may be in the CSS, and both need a pass. The @supports guard that activates the container query version is itself something you test. Open the console and run:

CSS.supports('container-type: inline-size')

A true return confirms the engine takes the modern path.

Responsive Design Breakpoint Testing: Continuous Resize Over Preset Widths

Breakpoint testing is not about checking a phone, a tablet, and a desktop width. It is about finding where your layout breaks between those points. The breakpoints you defined in your CSS are your targets. The breakpoints you did not define are your failures.

Three Failure Classes to Watch

Drag the viewport continuously from the narrowest width to the widest and watch for three failure classes. First, horizontal overflow. Check that no element causes the page to scroll sideways. Spot this by looking for a horizontal scrollbar on the <html> element. Second, text clipping: headlines that wrap to a single character, or paragraphs that collide with fixed-width sidebars. Third, layout collapse: grid items that overlap because a fixed track width exceeds the available space.

Use Responsive Mode, Not Presets

Use device mode’s responsive viewport mode for this, not the device preset list. The presets are for sanity checks at popular sizes, not for systematic testing. When you find a break that is not covered by your media query range syntax, you have two options: add a new breakpoint, or restructure so the break does not exist.

Resist the urge to add a breakpoint for every failure. Media query range syntax lets you write @media (width > 600px) and @media (width <= 600px) cleanly, but every extra breakpoint multiplies the states you have to test. The better fix is a fluid layout: minmax() in grid, clamp() for font sizes, and percentage-based tracks that absorb the intermediate widths without needing a conditional style.

CSS Layout Regression Testing: Automate What You Can, Manual Check the Rest

Manual breakpoint testing catches what you are looking for, but it misses what you forgot. CSS layout regression testing is the safety net that catches the unintended change: a padding edit that shifts the header 2px, a font size change that reflows the card grid, a new utility class that overrides a component’s width.

Screenshot Diffing

Two approaches exist. First, screenshot diffing: take a screenshot of your page at a fixed set of viewport widths before a change, take the same screenshots after, and diff them pixel by pixel. Tools like Playwright or Puppeteer can automate this in under a hundred lines of code. The diff highlights exactly which regions of the page changed, so you can verify whether the change was intended.

DOM Structural Assertion

Second, DOM structural assertion: check that the computed styles of key elements stay stable. This is where the computed styles panel in DevTools becomes a verification tool, not a debugging tool. Select an element, read the computed value of its width, margin, or grid-column, and assert that value in a test. This catches layout shifts that screenshot diffs might miss if the change is visually identical but semantically wrong.

Design your regression tests around the components that change most often: the header, the navigation, the card grid, and the footer. Run them in a CI pipeline on every commit. The Lighthouse responsive audit is not a substitute for this. It checks viewport-level health but does not catch component-level regressions.

Keep the test suite small. A regression test that takes ten minutes to run will not be run. A test that takes ten seconds will be run on every pull request. Target the ten most layout-sensitive components and lock their computed geometry.

Viewport Unit Testing Dvh Svh Lvh: the Dynamic Viewport Gap

Viewport unit testing is the area where DevTools lies to you. The dynamic viewport height unit dvh responds to the browser chrome collapsing and expanding. When the URL bar hides on mobile, dvh grows. The small viewport height unit svh is the height with the chrome fully visible. The large viewport height unit lvh is the height with the chrome fully hidden.

Why You Need a Real Device

Chrome DevTools device mode does not simulate the dynamic browser chrome. When you toggle device mode, the emulated viewport height is fixed. dvh, svh, and lvh all resolve to the same value. You can test the viewport meta tag. You can test the layout at different fixed heights. You cannot test the transition from svh to lvh or watch dvh animate as the chrome collapses.

The only way to test this is on a real mobile device or an emulator that simulates the chrome. On a real iPhone or Android phone, open your page, scroll down, and watch what happens to a fixed bottom bar that uses dvh. If you used height: 100dvh, the bar should sit at the bottom of the visible viewport with the chrome collapsed, and rise as the chrome expands.

The 100vh Bug and the Fix

The common bug: using 100vh for a full-screen section, which on mobile is taller than the visible viewport, pushing the bottom of the section off-screen. The fix: use 100dvh with a fallback to 100vh for engines that do not support dynamic units. Test both. Open the page on a phone with the URL bar visible, scroll to collapse it, then check the section bottom.

Firefox and Chrome on Android both ship dvh, svh, and lvh with Baseline status newly available. Safari shipped them in 15.4. The interop gap is not in support but in the behavior of dvh during momentum scrolling. Some engines update it eagerly, others settle it after the scroll ends. Test on both Android and iOS to see the difference.

Testing Container Queries with @supports and the Interop Dashboard

Before you write a single container query, confirm whether the engines you target support them. The @supports testing technique is the honest answer to the caniuse question, because it measures the engine you are actually in, not a global statistic.

Check Container Query Support

Open the console in each engine you need to support and run:

const supported = CSS.supports('container-type: inline-size');
console.log('Container queries:', supported);

If supported is true, the current engine parses container-type and will honor @container rules. If false, your fallback @media styles are the ones that paint.

Style Queries Need a Separate Check

The @supports check is not a proxy for every container query feature. Style queries, which respond to a container’s custom property value, shipped later than size queries. Safari 16.0 shipped size container queries, but style queries did not land until Safari 17. Run a second check:

const styleQueries = CSS.supports('@container style(--foo: bar)');
console.log('Style queries:', styleQueries);

Container units, cqw and cqh, have their own interop bugs. Older Safari versions that supported container queries still had incorrect rounding behavior on container units. The @supports check will pass for the unit syntax, but the computed value may be wrong by a fraction of a pixel.

Use the Interop Dashboard, Not Caniuse

For the real interop picture, go to the Interop dashboard. The Interop project publishes per-feature Web Platform Tests subtest pass rates across Chrome, Edge, Firefox, and Safari. A feature marked “shipped” on caniuse can still have failing subtests in an engine. The Interop gap is the number of failing WPT subtests, and that number is the one to quote in a bug report. The annual Interop project tracks container queries; check the dashboard rather than assuming the status is frozen.

Preference and Accessibility Emulation: Prefers-reduced-motion, Prefers-color-scheme, Forced-colors

Responsive design is not only about width. User preference media queries alter the layout, animation, and contrast of your page, and they are a legal requirement in many jurisdictions. The WCAG 2.2 success criterion 1.4.10 Reflow requires content to reflow without scrolling in two dimensions at 400% zoom. That is a direct test of your breakpoint coverage.

Emulating Color Scheme and Motion Preferences

Chrome DevTools device mode has an emulation panel for these preferences. Open the rendering tab, scroll to the “Emulate CSS media feature” section, and you can toggle prefers-color-scheme between light and dark, and prefers-reduced-motion between no-preference and reduce. Test here that your reduced-motion styles actually disable the animations that cause vestibular disturbance.

Testing Forced-Colors Mode

For forced-colors mode, the Windows High Contrast setting, you need more than the emulation panel. Chrome DevTools does emulate forced-colors in the rendering tab, but the real test is on the actual Windows machine with High Contrast enabled. Forced-colors mode testing is a requirement for government procurement in the United States (Section 508) and the European Union (EN 301 549). The CSS technique is the same across jurisdictions: use forced-color-adjust: none on the elements that must keep their own colors, and test that all meaning-carrying colors have non-color equivalents.

Zoom to 400% and Test Reflow

Zoom accessibility testing is separate from these emulations. Set the browser zoom to 400% and check that your layout reflows to a single column without horizontal scrolling. This tests your breakpoints at a different scale than device mode: zoom changes CSS pixel dimensions, so a 360px viewport at 400% zoom is effectively 90px of CSS width. If your smallest breakpoint is 320px, you will fail this test. Design for continuous reflow down to about 200px effective width, or accept that horizontal scrolling is the accessible fallback and ensure it is not hidden.

The Honest Limits of Browser-Based Testing

Every technique on this page has a boundary. DevTools device mode does not simulate the dynamic viewport. The container query inspector does not test the fallback @media styles. @supports checks tell you about parsing, not rendering correctness.

The Engine Is the Final Renderer

Describe what should happen under which conditions, and accept that the engine is the final renderer. A media query that passes in the DevTools emulation may behave differently on a real device with a different device pixel ratio, a different default font size, or a different operating system zoom level. The container query that fires at exactly 500px in your inspector may fire at 501px on a user’s machine because of scrollbar width differences.

When to Use Device Testing Services

Device testing services exist to close this gap. BrowserStack device testing gives you real devices in the cloud, and it is the only way to test dvh behavior on a physical iPhone without owning one. The cost is real money and slow iteration. Use it as a final verification pass, not as your primary testing loop.

The Polyfill Question

The other limit is the polyfill question. If you must support engines without container queries, you can run a container query polyfill. But a polyfill is a JavaScript dependency that recalculates layout on every resize. It can reintroduce the layout shift you are trying to avoid. Test the polyfilled version separately from the native version. A layout that works natively and breaks under the polyfill is a layout that fails for your users on older devices.

What to Do When a Breakpoint, Container Query, or Viewport Unit Fails

A failure in testing is a gift. It means you found a state you did not design for. The fix order is always the same: check the CSS parsing, check the computed values, check the container definition, then check the engine version.

When a Container Query Does Not Respond

If a container query is not responding, the first suspect is the container-type declaration. You must declare container-type: size or container-type: inline-size on the container. Without it, the element is not a container. The second suspect is the query name. If your @container card (width > 400px) names the container but the element that has container-type does not have container-name: card, the query cannot match.

When a Viewport Unit Is Wrong

If a viewport unit is wrong, check whether you are testing in an emulator that simulates the chrome. If not, move to a real device. If dvh is returning the same value as vh, your engine does not support dynamic units, and your fallback should be active.

When a Breakpoint Fires in DevTools but Not on the Device

If a @media breakpoint fires in DevTools but not on the device, check the device pixel ratio. A media query with a max-width in CSS pixels behaves differently at 2x and 3x scaling because the CSS pixel width of the viewport changes. Test at each device pixel ratio in device mode before deploying.

When the Computed Style Is Wrong

If the computed style of an element is not what your CSS declares, open the computed styles panel and look at the cascade. A more specific rule is overriding yours. The computed value is the truth; your source code is the intention.

What This Page Says That No Other Page Does

Chrome DevTools device mode cannot test container query breakpoints or dynamic viewport units, and the only way to test dvh, svh, and lvh behavior is on a real device with a collapsing browser chrome, because the emulator fixes the viewport height and resolves all three units to the same value.