Viewport Segments: The Foundation
Nearly three years after dual-screen devices first shipped, the web platform now has stable primitives for building layouts that account for the physical gap or hinge between displays. What's notable about these APIs is how deliberately they build on existing responsive design concepts. The CSS media features and JavaScript interfaces used for foldable and dual-screen support look and behave like familiar tools for targeting different screen sizes, rather than introducing a separate paradigm to learn.
Two generations of Samsung Galaxy Fold and Z Flip devices, along with the Surface Duo and Duo 2, are already in consumers' hands. That install base makes dual-screen and foldable support a practical consideration, not an experimental one. The APIs described below were shaped by developer feedback gathered during origin trials; the result is detection and layout tooling that integrates with media queries, the viewport, and environment variables.
Detecting Dual-Screen Postures In CSS
Foldable detection uses a new media feature that describes how many distinct viewport regions exist in each axis. Like other media features, you can combine it with width queries to scope styles precisely.
horizontal-viewport-segments
The horizontal-viewport-segments feature reports the number of viewports present in the horizontal direction. A device in a book-like posture with a vertical hinge yields two viewports split into columns.
horizonal-viewport-segment targets the device when the hinge is in the vertical fold posture. (Large preview)The following rule targets a foldable in that vertical-fold posture:
@media (horizontal-viewport-segments: 2) {
// Styles specific to the device in this orientation
}
The integer return value indicates the number of distinct viewports for the device orientation. With the device in vertical-fold posture (like an open book), there are two viewport regions horizontally and one vertically. You can also combine posture detection with viewport width checks to conditionally apply a more specific set of styles:
@media (horizontal-viewport-segments: 2) and (min-width: 540px) {
body {
background: yellow;
}
}
vertical-viewport-segments
For the opposite orientation, vertical-viewport-segments detects when the hinge is horizontal and splits the screen into stacked rows.
vertical-viewport-segments targets the device in the horizontal fold posture. (Large preview)To target a device rotated into that posture, use this query:
@media (vertical-viewport-segments: 2) {
// Styles specific to the device in this orientation
}
Detection From JavaScript
CSS media queries aren't always the right fit. In canvas-based contexts like WebGL or Canvas2D, the layout isn't defined in CSS, so you need programmatic access to the display geometry. The initial proposal for a dedicated Windows Segments Enumeration API was eventually replaced by an extension to the existing Visual Viewport API.
The segments property on visualViewport returns an immutable snapshot of the current display regions:
const segments = window.visualViewport.segments;
The result is an array of DOMRect objects, one per distinct viewport segment, when the window spans multiple displays. If only one display region exists, the API returns null — deliberately avoiding a truthy single-element array so developers won't start treating visualViewport.segments[0] as a standard single-screen path.
Because this is a snapshot, any change to the window or device invalidates the stored values. A browser window resized down to a single display region fires a resize event. Rotating the device fires both resize and orientation events. In either case, re-querying the property is required to obtain the updated state:
window.addEventListener("resize", function() {
const segments = window.visualViewport.segments;
console.log(segments.length); *// 1*
});
Choose the JavaScript API over the CSS media features when a project has no CSS layout to hook into — a game engine rendering to a canvas is the canonical example.
Environment Variables For Segment Geometry
Beyond posture detection, six CSS environment variables provide the actual coordinates and dimensions of each display region. These cover segment width and height, plus top, right, bottom, and left offsets:
env(viewport-segment-width <x> <y>)env(viewport-segment-height <x> <y>)env(viewport-segment-top <x> <y>)env(viewport-segment-left <x> <y>)env(viewport-segment-bottom <x> <y>)env(viewport-segment-right <x> <y>)
The x and y parameters identify a segment within a two-dimensional grid created by hardware separators. Coordinate 0,0 resolves to the top-left segment.
Interpretation depends on pose. In vertical-fold posture, the left viewport is env(viewport-segment-width 0 0) and the right is env(viewport-segment-width 1 0). Rotated to horizontal-fold posture, the top is env(viewport-segment-height 0 0) and the bottom is env(viewport-segment-height 0 1).
The width and height variables accept an optional fallback value appended after the indices, but including it is your choice:
env(viewport-segment-width 0 0, 100%);
Computing The Hinge Area
For hardware hinges that occlude part of the screen, you can derive the obscured gap by comparing segment edges. A test with the viewport in vertical posture earns the hinge width by subtracting the left edge of the right segment from the right edge of the left segment:
calc(env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0));
Positioning Against The Hinge
These environment variables are particularly useful for anchoring content to the inner edge of a display region. Take a design that should pin an image against the right side of the left viewport — exactly where a hinge or fold begins. Using the left property with viewport-segment-right might look like this:
img {
max-width: 400px;
}
@media (horizontal-viewport-segments: 2) {
img {
position: absolute;
left: env(viewport-segment-right 0 0);
}
}
Emulating Surface Duo in Edge Developer Tools shows the problem with a naive approach:
Because absolute positioning with left aligns the element's leftmost edge to the specified coordinate, the outcome lands in the wrong display entirely. Countering that offset is straightforward: subtract the element's own width from the environment variable:
img {
max-width: 400px;
}
@media (horizontal-viewport-segments: 2) {
img {
position: absolute;
left: calc(env(viewport-segment-right 0 0) - 400px);
}
}
The result is the intended hinge-aligned placement. For further placement patterns along the seam, a simple box demo is available; open Edge Developer Tools > Device Emulation, choose Surface Duo, and confirm the Duo emulation posture matches the one you're testing.
Adapting A Recipe Page To A Dual-Screen Device
A recipe site that reflows to fit a dual-screen device is a practical use case for these new layout APIs. Let’s examine how to adapt a single recipe page, starting with how content is chunked on a conventional desktop layout.
The core content for a typical recipe minimal set includes the title, servings, prep time, images, ingredients, and steps. The initial wireframe calls for the title and details on top, a full-width image below that, and then the ingredients and steps in two columns underneath. The decision to use two columns here avoids substantial white space to the right of the ingredient list.
Choosing A Layout Method
Several options exist for coding the desktop layout, such as combining flebox for grouped content with CSS Grid for the page structure. However, the grouping must account for the target dual-screen experience.
If the ingredients and steps are wrapped in a flex container, adapting them to sit apart on a dual screen would leave a large empty gap where the image column doesn't align.
CSS Grid alone provides the most control. Setting up the content and structure is straightforward:
<main>
<section class="recipe">
<div class="recipe-meta">
… <!—Contains our recipe title, yield and servings -->
</div>
<img src="imgs/pasta.jpg" alt="Pasta carbonara photographed from above on a rustic plate" />
<div class="recipe-details__ingredients">
…<!— Contains our ingredients list -->
</div>
<div class="recipe-details__preparation">
… <!— Contains our list of steps to put the ingredients together -->
</div>
</section>
</main>
Define a three-column grid where each column is an equal fraction of the container, using grid-auto-rows with minmax so rows have a minimum height of 175px but can expand as needed.
.recipe {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(175px, max-content);
Add the remaining layout properties, such as gap, max-width, and auto-centering margins.
grid-gap: 1rem;
max-width: 64rem;
margin: 0 auto;
}
Placing the content items into their grid areas produces the intended desktop layout.
.recipe-meta {
grid-column: 1 / 4;
}
.recipe-meta p {
margin: 0;
}
img {
width: 100%;
grid-column: 1 / 4;
}
.recipe-details__ingredients {
grid-row: 3;
}
.recipe-details__preparation {
grid-column: 2 / 4;
grid-row: 3;
}
Making The Layout Work Around The Hinge
Without further adjustments, the same layout on a dual screen would have content obscured by the hardware hinge.
The first fix is redefining the grid columns to use the CSS environment variable for viewport segments. The first column spans the full width of the left display area, while the other two columns fill the right display.
@media (horizontal-viewport-segments: 2) {
/* Body styles for smaller screens */
body {
font: 1.3em/1.8 base, 'Playfair Display', serif;
margin: 0;
}
.recipe {
grid-template-columns: env(viewport-segment-width 0 0 1fr 1fr;
grid-template-rows: repeat(2, 175px) minmax(175px, max-content);
}
}
For the rows, set the first two rows to a fixed 175px height to contain the top details, then let the rest behave as defined initially. The previously set width and margin on the container will incorrectly pull the gridlines away from the segment edges, so those need to be reset.
@media (horizontal-viewport-segments: 2) {
.recipe {
grid-template-columns: env(viewport-segment-width 0 0) 1fr 1fr;
grid-template-rows: repeat(2, 175px) minmax(175px, max-content);
margin: 0;
max-width: 100%;
}
}
Finally, position the content within this new grid. The image is allowed to span the entire viewport width. For content below the image—which now starts at the gridline under the hinge—extra padding is required to visually match the padding from the left edge. A 3rem left padding compensates for the existing 1rem grid gap and the hinge offset.
.recipe-meta {
grid-column: 1 / 2;
padding: 0 2rem;
}
img {
grid-column: 2 / 4;
grid-row: 1 / 3;
width: 100%;
height: 100%;
object-fit: cover;
/* necessary to keep the image within the grid lines */
}
.recipe-details__ingredients {
grid-row: 2;
padding: 0 2rem;
}
.recipe-details__preparation {
grid-column: 2 / 4;
grid-row: 3;
padding: 0 2rem 0 3rem;
}
This yields a fully responsive dual-screen layout with only modest CSS changes using the new media feature. For small single-screen devices, the fallback layout is simple flexbox in a single column.
@media (max-width: 48rem) {
body {
font: 1.3em/1.8 base, 'Playfair Display', serif;
}
.recipe-details {
display: flex;
flex-direction: column;
}
}
Availability And Testing
These dual-screen APIs are enabled by default in Microsoft Edge (and Edge on Android) starting with version 97. Other Chromium browsers don’t have a confirmed release date but will likely support them soon. In Chrome, you can test by enabling chrome://flags → experimental web platform features.
If you lack a physical device, browser developer tools are reliable. Emulation, particularly for the Surface Duo, matches the device experience closely. For non-supporting browsers, a polyfill exists for the Visual Viewport segments API. The CSS media queries have no equivalent polyfill.
Current dual-screen devices run Android, so users can choose to span a site across one screen or both. A site without dual-screen styling still works as a regular single-screen layout if the user opts for that view. However, the APIs allow you to progressively enhance for the device’s full capabilities.
From a practical standpoint, integrating these features with existing sites is a natural extension of responsive design. Microsoft’sSurface Duo documentation offers additional guidance. Emerging display technologies signal an opportunity for more creative and flexible web layouts.
Further Resources
- “Dual-Screen Web Experiences,” Microsoft
- “Horizontal Viewport Segments: The
horizontal-viewport-segmentsFeature,” Media Queries Level 5, W3C Working Draft (Dec. 2021) - “Viewport Segment Variables,” CSS Environment Variables Module Level 1, Editor’s Draft (Aug. 2021)
- “Visual Viewport API,” Draft Community Group Report (Feb. 2022)
For the live demo and to see the code in action, visit the demo site on Edge or a Chromium browser with it enabled under the aforementioned flags. This exploration shows that responsive design is evolving to encompass new device shapes, making dual screens the next frontier in web layout.



