iPhone Duo ships on October 23. Most "is my site ready?" guides quote viewport sizes worked out from the spec sheet — screen pixels divided by three: 466 × 678 folded, 626 × 890 or 890 × 626 unfolded.
That isn't what your page gets. I opened a probe page in Safari on the iPhone Duo simulator (Xcode 27.1) and logged what the page actually receives in each pose. A few results surprised me, and two of them I haven't seen written down anywhere.
The numbers
| Pose | What the page gets (innerWidth × innerHeight) |
|
|---|---|---|
| Folded | 382 × 580 | Safari puts its status bar and buttons in a column on the right. The screen is 466 wide; your page is 84 px narrower. |
| Unfolded, upright | 669 × 825 | Between Tailwind's sm (640) and md (768) — a band few sites test. |
| Unfolded, sideways | 951 × 543 | Desktop width. Still a finger. Only 543 px tall. |
| Folded, sideways | 678 × 340 | The shortest pose of all. |
The inner display itself is 2853 × 2007 px = 951 × 669 pt in the simulator, so even the "626 × 890 screen" figure going around doesn't match.
Every pose reports (pointer: coarse) and no hover. Folding or unfolding fires resize; the page is not reloaded. screen.width keeps the folded value (466) after you unfold, so don't size anything from screen.
1. Wide doesn't mean mouse
At 951 px most sites switch to their desktop layout. That's where this pattern lives:
<!-- hidden on "desktop", shown on hover -->
<button class="opacity-100 sm:opacity-0 group-hover:opacity-100">Edit</button>
On an unfolded Duo — or any iPad — that button is never visible, because a finger has no hover. Gate it on the input, not the width:
@media (hover: hover) and (pointer: fine) {
.row .edit { opacity: 0; }
.row:hover .edit { opacity: 1; }
}
2. Half-folding is invisible to the web
I expected the half-open "tabletop" pose to show up somewhere — Viewport Segments, Device Posture, a media query. Nothing. When you half-fold the phone, Safari moves to the outer screen and the page gets exactly the folded viewport, 382 × 580. No posture event, no segments, all posture media queries false.
So on iPhone Duo there are only two states the web can see: folded and open. You don't need a tabletop layout — and you can't build one.
3. One fold fires 2–3 resizes, through a size that belongs to no pose
I logged every resize while folding and unfolding:
resize → 466 × 498 ← transient: no pose has this size
orientation → landscape
resize → 951 × 543 ← open
The 466 × 498 step happens mid-swing, while the screens are switching over. If your code re-lays out on every resize, it does that work for a frame nobody sees. Worse, a list–detail layout that docks the detail beside the list above some width will flip to a drawer and back in one gesture.
Wait for the size to settle (~150 ms of no resizes) before switching layouts. If you measure with ResizeObserver, debounce the decision, not the measurement.
4. 100vh is taller than the page
Folded, Safari gives the page 580 px of height:
100vh / 100lvh
|
598 — 18 px too tall |
100dvh / 100svh
|
580 — correct at rest |
A full-height sheet sized with vh hides its bottom button. dvh is right — until the keyboard opens, at which point no viewport unit follows it. Read visualViewport.height for that.
5. Safari's right-hand column ignores theme-color
Folded, Safari's controls live in a column to the right of your page, and they don't use theme-color. Safari samples the page edge instead, and only from fixed or sticky elements. People have tried widening the page to the edge to colour it, which causes horizontal scrolling.
What worked in the simulator: an 8 px position: fixed strip on the right edge. The whole column takes its colour, and scrollWidth stays at 382 — no horizontal scroll.
.toolbar-tint { position: fixed; top: 0; right: 0; bottom: 0; width: 8px;
background: #1e3a8a; pointer-events: none; }
Give it the colour of whatever is next to it, so it reads as part of the page.
What I'd check before Thursday
- Search for width-gated hover:
sm:opacity-0,md:hiddenon controls,:hoverrules outside(hover: hover). - Open your site at 669 px wide — between your breakpoints.
- Look at your layout at 951 × 543 with touch emulation on. Is the header eating half the height?
- Replace
100vhwith100dvh(keepvhas a fallback). - Delete user-agent checks — the Duo says plain
iPhone. - Don't debounce resizing in general, but do let a fold settle before swapping layouts.
I packaged this up
All of the above came out of adapting a real app (a school management system our teachers use on PCs, iPads and phones), so I pulled the reusable parts into a small React library, fold-ready — zero dependencies, SSR-safe, React 17+:
import { SplitHost, Pane, useSelection, KeepPlace, ToolbarTint } from "fold-ready";
function Inbox({ mails }) {
const [sel, setSel] = useSelection("sel"); // ?sel=42, survives reload
const open = mails.find((m) => m.id === sel);
return (
<SplitHost> {/* docks side by side for wide touch screens */}
<KeepPlace> {/* same row on top after a fold */}
<MailList mails={mails} onOpen={(m) => setSel(m.id)} />
</KeepPlace>
{open && <Pane label="Message" onClose={() => setSel(null)}>…</Pane>}
</SplitHost>
);
}
-
useInputMode()→{ touch, hover, short }, plus Tailwind variantscan-hover:touch:short: -
SplitHost+Pane: detail docks beside the list when there's room on a touch screen, drawer otherwise; waits for a fold to settle -
KeepPlace: keeps the same item at the top (and your caret) when the width changes -
ToolbarTint,useVisibleViewport,useSettledViewport -
FoldReadyInspector: a dev overlay that finds hover-only controls on the current page
Mouse users keep the behaviour they had unless you opt in.
Duo Lab shows any URL in the measured poses and plays the fold step by step — including that 466 × 498 frame: https://tyoukyou23.github.io/fold-ready/#/lab
Code: https://github.com/tyoukyou23/fold-ready · npm: fold-ready
Caveat
These are simulator numbers. I'll check them on hardware when the phone arrives. If you have a Duo before I do, the demo's Measure page prints what your Safari reports and copies it as JSON — I'd love to compare: https://tyoukyou23.github.io/fold-ready/#/measure
Top comments (0)