应使用 css 媒体特性 screen-spanning 配合 env() 环境变量识别折叠屏双屏布局:仅在跨折叠线渲染时匹配 single-fold-horizontal/vertical,再通过 env(fold-top) 或 env(fold-left) 获取折叠线位置实现精准避让。

如何识别折叠屏设备的双屏布局状态
折叠屏设备(如 Samsung Galaxy Z Fold 系列、Microsoft Surface Duo)在展开后会暴露两个独立的 screen 区域,但浏览器仍报告单个 window.screen。真正可用的信号来自 CSS 媒体特性:screen-spanning 和 horizontal/vertical-viewport-segment —— 这些是 W3C 提出的折叠屏专属媒体特性,目前仅 Chromium 119+(含 Edge 119+、Chrome Canary)原生支持。
关键判断逻辑是:只有当设备处于展开态且应用跨屏显示时,@media (screen-spanning: single-fold-horizontal) 或 @media (screen-spanning: single-fold-vertical) 才会匹配。注意,screen-spanning 不会在折叠态触发,也**不会**在单屏全屏模式下触发 —— 它专为「跨折叠线渲染」而设。
-
screen-spanning: single-fold-horizontal→ 折叠线水平(如 Z Fold 横向展开,两屏上下排列) -
screen-spanning: single-fold-vertical→ 折叠线垂直(如 Surface Duo 展开,两屏左右并排) - 不支持该特性的浏览器(如 Safari、旧版 Chrome)会直接忽略整个媒体查询块,需配合回退方案
用 env() 读取折叠线位置做精准布局避让
光靠媒体查询判断“是否跨屏”还不够——你还需要知道折叠线在哪,避免按钮、输入框或关键内容被遮挡或落在折痕上。CSS 提供了环境变量 env(fold-top)、env(fold-left)、env(fold-width)、env(fold-height),它们在跨屏时返回像素值(如 env(fold-left) 在 vertical 折叠时返回左屏右边界 x 坐标)。
这些变量只在匹配 screen-spanning 媒体查询时有效,且值为 0px 或未定义时代表不可用。务必用 @supports (environment(fold-top)) 做特性检测,而不是直接写死。
- 横向折叠(上下双屏):用
env(fold-top)+env(fold-height)判断安全区域上下边界 - 纵向折叠(左右双屏):用
env(fold-left)+env(fold-width)计算左右屏分隔线 - 不要用
calc(100vh - env(fold-height))直接切分高度——实际可用高度还受状态栏、系统UI影响,应结合env(viewport-height)回退
为什么 min-width / max-height 在折叠屏上容易失效
传统响应式依赖视口尺寸(width、height),但在折叠屏上,展开态的 window.innerWidth 可能仍是折叠态数值(尤其 Android WebView 或 PWA 启动时),且系统可能限制 Web 内容仅渲染在单屏。这意味着 @media (min-width: 1200px) 可能在双屏总宽达 1440px 时也不匹配。
根本问题在于:视口尺寸 ≠ 物理屏幕能力。折叠屏的“响应”本质是拓扑变化,不是尺寸缩放。硬套桌面断点会漏掉关键状态,比如 Z Fold 展开后横屏宽度 1200px,但若应用未声明跨屏 intent(Android 的 androidx.window 配置),系统仍只分配单屏资源。
- Android PWA 必须在
manifest.json中添加"display_override": ["window-controls-overlay", "minimal-ui"]并配合intent-filter声明跨屏支持 - 不要用
matchMedia监听width变化来判断折叠状态——它无法捕获screen-spanning切换 - 服务端 UA 检测无意义:Z Fold 和 Pixel 7 的 UA 字符串几乎一致,无法区分折叠态
一个最小可行的跨屏样式示例
下面这段 CSS 在 Chromium 119+ 中生效,同时对不支持的浏览器完全静默(无副作用):
@supports (environment(fold-top)) {
@media (screen-spanning: single-fold-vertical) {
.sidebar {
width: calc(env(fold-left) - 16px); /* 左屏留白,避开折叠线 */
flex-shrink: 0;
}
.main-content {
margin-left: calc(env(fold-left) + env(fold-width) + 16px); /* 从右屏起始位置开始 */
width: calc(100vw - env(fold-left) - env(fold-width) - 32px);
}
}
}
<p>/<em> 回退:当不支持 env() 但检测到大屏时,按常规双栏处理 </em>/
@supports not (environment(fold-top)) {
@media (min-width: 1200px) {
.sidebar { width: 240px; }
.main-content { margin-left: 256px; }
}
}</p>
注意 env() 必须出现在 @supports 块内,否则旧浏览器会因语法错误丢弃整条规则;calc() 中的单位必须显式写出(16px,不能是 16),否则计算失败。
真实项目里,折叠线位置可能随系统手势栏动态变化,env() 值会实时更新,但重排开销较大——别在 env(fold-left) 上做高频动画,也别把它当 JS 变量反复读取。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











