In September, a post titled "Dear God websites look horrible on iPhone Duo" climbed to the top of r/webdev. Two screenshots and one complaint: with the phone closed, sites were using about 70% of the screen. It passed 3,000 upvotes. Much of the thread was aimed at Safari for keeping its controls on screen on the smaller, closed display. Fair. But plenty of the ugliness in those screenshots was ours: layouts built for three fixed widths.
Pre-orders open October 16. The phone goes on sale October 23. Below is the checklist we'd work through before then. Nothing here assumes you own the device, because almost nobody does yet.
First, the numbers (and why you shouldn't trust them)
Apple publishes physical pixels only. The inner display is 1878 x 2670 and the outer one is 1398 x 2034. Divide by the usual iPhone pixel ratio of 3 and you get the commonly quoted estimates:
| State | Screen in CSS px (estimated) |
|---|---|
| Closed, outer display | about 466 x 678 |
| Open, held like a book | about 890 x 626 |
| Open, rotated | about 626 x 890 |
The open device is wider than it is tall (164.6 mm by 117.8 mm), which is why most write-ups quote 890 as the unfolded width. So the jump people talk about, 466 to 890 in one motion with no reload, is real in the common case.
Now the catch. Safari on the Duo keeps a strip of controls down the right edge. One design studio, working in Apple's iOS 27.1 simulator, measured the outer screen's web view at 466 points but the layout viewport at 382. That means innerWidth may be smaller than every number in the table.
Treat the table as a test plan. Never treat it as a breakpoint list.
1. Find out where your breakpoints actually land
Default framework breakpoints were not designed with this phone in mind. At 890px, Tailwind and Bootstrap both serve their md (768px) tier, which most teams treat as "tablet portrait". At 626px, Tailwind's first step (sm, 640px) doesn't fire at all, so a 7.6-inch screen gets the exact CSS of a 6.3-inch iPhone.
Paste this into DevTools on your production site to see what you're really shipping:
// Lists every width breakpoint in same-origin stylesheets.
const widths = new Set();
let skipped = 0;
const walk = (rules) => {
for (const rule of rules) {
if (rule instanceof CSSMediaRule && /width/.test(rule.conditionText)) {
for (const [, n, unit] of rule.conditionText.matchAll(/(\d+(?:\.\d+)?)(px|em|rem)/g)) {
widths.add(unit === 'px' ? Number(n) : Number(n) * 16);
}
}
if (rule.cssRules) walk(rule.cssRules);
}
};
for (const sheet of document.styleSheets) {
try { walk(sheet.cssRules); } catch { skipped++; }
}
console.log([...widths].sort((a, b) => a - b), `${skipped} cross-origin sheets skipped`);
If skipped is above zero, the list is incomplete. Check where 382, 466, 626 and 890 fall. If two of them hit the same tier and the layout looks wrong at one of them, you've found your first bug.
Don't fix it with @media (width: 890px). The next foldable will ship different numbers. Move the boundary to wherever your content starts to look cramped or stretched.
2. Let components respond to their container
Page breakpoints answer "how wide is the window?" Most layout bugs on the Duo are really "how wide is this card?" Container queries answer that directly, and they keep working in Split View, where your page might be half the inner screen.
.card-list {
container: cards / inline-size;
}
.card {
display: grid;
gap: 1rem;
}
@container cards (width >= 34rem) {
.card {
grid-template-columns: 12rem 1fr;
align-items: start;
}
}
The card now goes side by side when its column has room, whether that's on an unfolded Duo, a laptop or a narrow sidebar. Forms, pricing tables and product grids benefit the most.
3. Stop sizing heroes with 100vh
vh maps to the large viewport, the size with browser UI retracted. On a 678px-tall outer screen, a 100vh hero with a headline, a subhead and a button can push the button below the fold.
.hero {
min-height: 100vh; /* fallback for old browsers */
min-height: 100svh; /* small viewport: never taller than what's visible */
}
.app-shell {
height: 100dvh; /* dynamic: follows toolbars as they move */
}
Our rule: svh for marketing heroes, dvh for full-screen app shells, vh almost nowhere. One caveat worth checking yourself: the same studio reported 100vh resolving to 598 on a 678px outer screen in the simulator, and said no CSS unit matched the visible height under Safari's floating toolbar. Open your hero in the simulator and look before you trust any unit.
4. A wide screen is not a mouse
At 890px, plenty of sites switch to the desktop nav. That nav usually opens on :hover. On a touch screen, hover is emulated with an awkward tap, so the mega menu either flickers or never opens.
Gate hover behaviour on the input type instead:
.nav-item > .submenu { display: none; }
/* Works everywhere: keyboard focus and an explicit toggle */
.nav-item:focus-within > .submenu,
.nav-item[data-open] > .submenu { display: block; }
/* Only real hover devices get hover menus */
@media (hover: hover) and (pointer: fine) {
.nav-item:hover > .submenu { display: block; }
}
/* Bigger hit areas for fingers */
@media (pointer: coarse) {
.nav-item > a,
.nav-item > button { min-block-size: 2.75rem; }
}
hover and pointer describe the primary input. If you need "does any input hover?", use any-hover and any-pointer. Apple says Apple Pencil support for the Duo arrives later this year, which is one more reason not to bake "this phone never hovers" into your JavaScript.
5. Make your JavaScript resize-safe
CSS reflows on its own. JavaScript that measured once at load does not. Look for these in your codebase: const isMobile = window.innerWidth < 768, chart libraries initialised with a fixed width, carousels that calculate slide counts on mount.
Use a media query listener for layout modes and ResizeObserver for element sizes:
const wide = window.matchMedia('(width >= 48rem)');
function setLayout(isWide) {
document.documentElement.dataset.layout = isWide ? 'wide' : 'narrow';
}
setLayout(wide.matches);
wide.addEventListener('change', (e) => setLayout(e.matches));
const chartBox = document.querySelector('.chart-wrap');
const ro = new ResizeObserver(([entry]) => {
chart.resize(Math.round(entry.contentRect.width));
});
ro.observe(chartBox);
Both are Baseline widely available. The harder bug is state. If your framework unmounts the mobile nav and mounts a desktop one at a breakpoint, the user unfolds the phone and loses whatever they typed, the open accordion and sometimes their scroll position. Prefer one component that restyles over two components that swap.
6. Delete user-agent layout branching
The Duo identifies as an iPhone. Code like this serves your phone layout to a screen with room for a sidebar:
// Wrong on the largest iPhone Apple has made
const isMobile = /iPhone/.test(navigator.userAgent);
Search your repo, your tag manager and your server templates for this pattern. Replace it with media queries, container queries, or matchMedia checks that listen for changes.
7. Split your safe-area padding
If you draw edge to edge, safe-area values only apply with viewport-fit=cover in the viewport meta. On the Duo, the left and right insets are reported to differ, so the old shorthand that copies one value to both sides is a quiet bug:
/* Before */
.toolbar { padding-inline: env(safe-area-inset-left); }
/* After */
.toolbar {
padding-left: max(1rem, env(safe-area-inset-left));
padding-right: max(1rem, env(safe-area-inset-right));
}
Reports conflict on whether Safari's right-hand control strip shows up in these insets at all, so verify with your own eyes in the simulator. And keep your primary call to action out of the dead centre of wide layouts. That's where the fold runs, and right now CSS can't tell you exactly where it is.
8. Don't wait for fold detection
The web has APIs for this: Viewport Segments (horizontal-viewport-segments, visualViewport.segments) and Device Posture. Chrome supports them on Android foldables. WebKit's standards-positions issue for Viewport Segments, filed in March 2024, is still open with no stated position. A commenter on that issue noted in September that the feature appears behind a flag in the iOS 27.1 simulator. Behind a flag means your visitors won't have it.
Write the single-viewport layout first and treat segments as an extra:
const segments = window.visualViewport?.segments;
if (segments && segments.length > 1) {
document.documentElement.dataset.fold = 'split';
} else {
delete document.documentElement.dataset.fold;
}
9. Test the unfold itself
A static screenshot at 890px tells you very little. The bugs happen during the transition. Here's the loop we'd run:
- In Chrome or Safari responsive mode, set 466 x 678. Open the menu, type into a form, scroll halfway down a long page.
- Without reloading, switch to 890 x 626. Then 626 x 890. Then back to 466.
- Check what survived: scroll position, form input, open menus, playing video, sticky headers.
Add a dev-only logger so you can see what fired and when:
new ResizeObserver(() => {
console.log('viewport', innerWidth, 'x', innerHeight);
}).observe(document.documentElement);
On a Mac, you can go further. Per one studio's walkthrough, the Duo only appears in the iOS 27.1 simulator, and Xcode 27 moves simulators into an app called Device Hub:
xcrun simctl create "iPhone Duo" com.apple.CoreSimulator.SimDeviceType.iPhone-Duo com.apple.CoreSimulator.SimRuntime.iOS-27-1
xcrun simctl boot "iPhone Duo"
xcrun simctl openurl booted http://localhost:5173
Safari's Develop menu on the Mac then attaches Web Inspector to the simulator page. Also drag the Split View divider through its full range, since that resizes your page to widths no device table lists.
The short version for site owners
If you don't write code, ask whoever maintains your site two questions this week. What does our site look like at 466 and 890 pixels wide? And what happens to a half-filled enquiry form when the phone opens? Layout bugs like these rarely throw errors. They just lose leads quietly, which is the same pattern behind most of the reasons startup websites fail to generate leads that we've written about before.
Which of these bit you first? We're especially curious whether anyone has a clean answer for Safari's side strip yet.
Sources
- Apple Newsroom, iPhone Duo announcement (dates, displays, Split View, Apple Pencil): https://www.apple.com/in/newsroom/2026/09/apple-unveils-iphone-duo
- Apple, iPhone Duo tech specs (pixel dimensions, physical size): https://www.apple.com/iphone-duo/specs/
- screensize.io, iPhone Duo viewport estimates: https://www.screensize.io/blog/iphone-duo.html
- MDN on viewport units, container queries,
hover,pointer,ResizeObserver: https://developer.mozilla.org/ - WebKit standards position on Viewport Segments: https://github.com/WebKit/standards-positions/issues/327
Written by the team at Clydara, a web and software studio in Lahore that builds and fixes sites like these for clients. We used AI tools to help with research and drafting, and checked every claim against the sources above.
Top comments (0)