返回动态列表

Web 网页应用如何适配 iPhone Duo 上的 Safari?

Apple 还没有发布 web 适配指南,WebKit 官方博客是目前唯一可信的参考:先按响应式设计做,再用 Device Posture API 与 Viewport Segments API 处理折叠状态,最后别忽略外屏侧边的控件区。

适配指南Safari

截至 2026 年 10 月 28 日,Apple 还没有发布任何面向 web 的 iPhone Duo 适配指南。目前唯一一份来自官方的技术说明,是 WebKit 博客 10 月 23 日的《WebKit Features for Safari 27.1》。

这篇文章的核心结论只有一句:没有新闻。iPhone Duo 上的 Safari 用的是同一套 WebKit、同一批 web 技术,网站与 web 应用照常工作,不需要为它单独做一个版本。

但「照常工作」不等于「什么都不用管」。下面按能落地的顺序拆开:先看视口范围,再讲 iPhone Duo折叠屏网页适配的基本盘,然后是 Safari 折叠屏适配里唯一由系统接管的行为,接着回答 web 如何判断折叠屏状态、web 如何判断设备是折叠屏这两个最容易混淆的问题,最后给出网页如何适配iPhone Duo 的清单。

一、先看视口:382 到 951

WebKit 给了一张 Safari 27.1 的视口表,覆盖各种姿态(CSS 像素):

姿态 宽度 SVH LVH
外屏,竖屏 382 580 618
外屏,横屏 594 368 406
内屏,竖屏(单标签页) 669 867 902
内屏,横屏(单标签页) 951 585 620
内屏,横屏双窗口(每个窗口) 385 571 609

三条结论:

  • 宽度范围是 382–951,高度范围是 368–902。 这个区间和其他 iPhone 有重叠,所以不能靠宽度反推机型。
  • 内屏的标签栏在顶部,像 iPad 或 Mac;外屏在底部,和普通 iPhone 一样。用户滚动时,标签栏会缩小。
  • 内屏横屏可以并排两个窗口,每个窗口拿到的是一个窄的竖屏视口(385 宽)。

这些数字不需要写进代码。用媒体查询加 Grid / Flex 的流体布局把 382–951 整个区间覆盖住就够了。

二、iPhone Duo折叠屏网页适配:先做响应式,别做设备嗅探

WebKit 的建议很直接:不要用 UA 嗅探判断设备,改用特性检测。理由不只是「UA 不可靠」——折叠屏的姿态变化本来就不会反映在 UA 里,而且 Duo 的视口和普通 iPhone 有交集。

iPhone Duo折叠屏网页适配的第一层,其实就是最普通的响应式设计:

.grid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
}

再补两条容易忽略的:

  • 高度别用 100vh。 表格里的 SVH / LVH 两列已经说明了浏览器工具栏会伸缩;优先用 svh、lvh、dvh。
  • 断点按内容宽度定,不按机型定。 320 / 480 / 720 这类通用断点比「Duo 内屏 669」更稳,设备换代也不用改。

三、Safari 折叠屏适配:唯一被系统接管的是 PDF

Safari 27.1 面向用户只改了一件事:当用户像看书一样半折着看网页 PDF 时,Safari 自动把 PDF 显示成左右两页;摊平或完全合上后,回到单页。

这是浏览器行为,网站不需要做任何事,也没有 CSS 能控制它。所以 Safari 折叠屏适配的重点不在 PDF,而在两件事:视口变化时布局别崩,控件位置变了别挡住内容。

除此之外,Safari 并没有为折叠屏增加「自动分栏」「自动重新排版」之类的能力。想在半折时把内容分到两侧,得自己写,也就是下面两个 API。

四、web 如何判断折叠屏状态:Device Posture API

Safari 27.1 在 iPhone Duo 上以开发者预览的形式提供了 Device Posture API 和 Viewport Segments API,默认关闭。打开路径是:设置 > App > Safari > 高级 > 功能开关,把「Device Posture API」和「Viewport Segments API」都打开。

Device Posture API 只有两个值:

  • folded:设备处于部分折叠,书本或笔记本姿态;
  • continuous:屏幕是平的,包含完全展开和完全合上。

CSS 里用媒体查询:

@media (device-posture: folded) {
  .layout {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

JavaScript 里读 navigator.devicePosture.type,并监听 change 事件:

function reportPosture() {
  console.log(`Device posture: ${navigator.devicePosture.type}`);
}

reportPosture();
navigator.devicePosture.addEventListener("change", reportPosture);

一个必须记住的边界:continuous 把「完全展开」和「完全合上」合并成了一个值。所以 web 如何判断折叠屏状态这个问题,API 只能回答「现在是不是半折」,回答不了「现在用的是内屏还是外屏」。

五、web 如何判断设备是折叠屏:没有可靠答案,也不该判断

这是最容易写错的一节。Device Posture API 只能描述当前姿态,不能说明设备身份:

  • 普通 iPhone 上,navigator.devicePosture 可能根本不存在;
  • 折叠屏完全摊平时,type 也是 continuous,和普通 iPhone 无法区分;
  • UA 字符串同样不行,WebKit 明确建议不要做 UA 嗅探。

所以严格来说,web 如何判断设备是折叠屏,目前没有官方答案。能做的是能力探测,不是设备判定:

const hasPosture = "devicePosture" in navigator;
const segments = window.viewport?.segments ?? [];

即便探测到 window.viewport.segments 返回两段,那也只能说明「当前屏幕被折痕分成两块」,不能反推设备型号:内屏横屏并排两个窗口时,同样是两块视口。

正确的思路是放弃「判断设备」,改成「判断可用空间」:空间够就上双栏,不够就单栏;半折且 API 可用时再按折痕对齐。这样无论将来出什么形态,布局都不用重写。

六、Viewport Segments:真正能绕开折痕的 API

Viewport Segments API 描述的是折痕两侧的「段」。Safari 27.1 在功能开关打开后支持两个媒体查询:

  • horizontal-viewport-segments: 2:左右并排,书本姿态;
  • vertical-viewport-segments: 2:上下堆叠,笔记本姿态。

要让内容精确贴合每一段的边缘,API 提供六个环境变量:viewport-segment-width、viewport-segment-height、viewport-segment-top、viewport-segment-right、viewport-segment-bottom、viewport-segment-left。每个变量带两个索引:先列、后行,从左上角的 0 0 开始。并排时左边是 0 0、右边是 1 0;堆叠时上边是 0 0、下边是 0 1。

@media (horizontal-viewport-segments: 2) {
  .wrapper {
    display: grid;
    grid-template-columns:
      env(viewport-segment-width 0 0)
      env(viewport-segment-width 1 0);
  }
}

JavaScript 侧用 window.viewport.segments 拿到一组 DOMRect,姿态变化或窗口尺寸变化时重读:

function reportSegments() {
  window.viewport.segments.forEach((segment, i) => {
    console.log(`Segment ${i}: ${segment.width}px × ${segment.height}px`);
  });
}

reportSegments();
navigator.devicePosture.addEventListener("change", reportSegments);
window.addEventListener("resize", reportSegments);

要提醒的是,这两个 API 现在都在功能开关后面,真实用户默认关闭。所以它们只能当增强手段,不能当唯一布局方案——没开开关时,页面必须仍然完整可读,靠的还是第二节那套响应式布局。

七、外屏侧边控件:背景色是现在唯一能做的事

外屏比普通 iPhone 更宽更短,iOS 为了把垂直空间留给内容,把控件移到了侧边。

Safari 27.1 里,网页内容目前不会延伸到这些控件后面。Safari 会读取页面背景色,用它把控件周围的空间铺满。WebKit 说他们在考虑放开这块区域,也提到 viewport-fit=cover 这个方向,但同时承认:现状是很多站点四边安全区都没处理对,所以还在找一个更稳妥的方案,目前没有结论。

在官方方案落地前,能做的只有三件小事:

  • 给 body 设一个和页面顶部一致的背景色,避免侧边出现割裂的色块;
  • 固定定位元素用 env(safe-area-inset-*) 留边距,别贴着屏幕边缘;
  • 注意顶部粘性导航:内屏标签栏在顶部,粘性头部不要和它抢同一块位置。

八、网页如何适配iPhone Duo:六步清单

  1. 媒体查询覆盖 382–951px,断点按内容宽度写,不按机型写;
  2. 高度用 svh / lvh / dvh,不用 100vh;
  3. 用 @media (device-posture: folded) 做半折时的分栏增强,不支持时保持单栏;
  4. 需要贴着折痕排版时,用 Viewport Segments 的 env() 对齐两侧;
  5. 所有折叠相关样式都放在特性检测之后,功能开关没开时页面依然完整;
  6. 用 Xcode 27.1 或更高版本的 Device Hub 模拟器测各种姿态,不必等真机。

九、测试:不用真机

WebKit 明确说,测试不需要 iPhone Duo 在手:下载 Xcode 27.1 或更高版本,用 Device Hub 创建 iPhone Duo 模拟器即可。在模拟器里的 Safari 打开功能开关,就能验证姿态与分段。

需要过一遍的姿态:外屏竖屏、外屏横屏、内屏竖屏、内屏横屏、内屏横屏双窗口、半折书本、半折笔记本。重点看三处:内容有没有被折痕或控件挡住、展开合拢时状态有没有丢、双栏在 385px 宽的窗口里会不会挤爆。

十、参考

Apple 官方 web 适配指南尚未发布,本文依据 2026 年 10 月 23 日的 WebKit 博客整理;官方文档上线后以原文为准。如果你的站点在 Duo 上遇到了上面没覆盖的问题,欢迎通过页脚的反馈表单告诉我们。