必须用 horizontal-viewport-segments 和 vertical-viewport-segments 媒体特性检测真实物理分屏状态,配合 @supports 保护,结合 css 变量驱动三态布局,并用防抖 matchmedia 监听 visualviewport 宽度实现稳定适配。

直接用 @media (min-width: 720px) 或 @media (orientation: landscape) 做折叠屏适配,基本无效——它既抓不住 Z Fold 展开时的双视口状态,也分不清 Pocket 翻盖后的上下分割,布局会错乱或漏判。
怎么检测真实物理分屏状态
必须用 horizontal-viewport-segments 和 vertical-viewport-segments 这两个媒体特性,它们是当前唯一被 Chrome/Edge 119+、Safari 16.4+ 正式支持的硬件级信号。
-
horizontal-viewport-segments: 2表示设备为竖折(如 Z Fold 展开),左右两个独立 viewport 渲染,document.body.clientWidth返回单侧宽度(约 375–420px) -
vertical-viewport-segments: 2表示设备为横折(如 Pocket 或 Z Flip 展开),上下两个独立 viewport 激活,此时才该用 height 相关布局 - 值只能是整数
1或2,写成horizontal-viewport-segments > 1或vertical-viewport-segments: 3全部无效 - 不要混用
screen-spanning——它已被 Chromium 废弃,MDN 已移除文档,真机上几乎永远不匹配
为什么必须套 @supports
这些媒体特性在 Safari/Firefox 和旧版 Chrome 中会被直接忽略,不加保护会导致整段样式失效,页面退化为单屏逻辑。
- 正确写法:
@supports (horizontal-viewport-segments: 2) { @media (horizontal-viewport-segments: 2) { ... } } - 错误写法:
@media (min-width: 768px) and (horizontal-viewport-segments: 2)——min-width查总宽,horizontal-viewport-segments: 2只在单侧渲染时为真,逻辑冲突,部分浏览器静默丢弃整条规则 - 降级必须显式:未匹配任何分段时,
:root中要设默认值,比如--fold-state: single,否则var(--fold-state)为unset,后续 calc 或 transition 都可能中断
如何用 CSS 变量驱动三态布局
别写 .sidebar--expanded / .sidebar--collapsed 两套 class,真实需求是窄(320px)、中(600px)、宽(960px)三态,且需平滑过渡。
- 定义基础变量:
:root { --sidebar-span: 320px; } - 双屏水平态:
@media (horizontal-viewport-segments: 2) { :root { --sidebar-span: 600px; } } - 大屏展开态(非折叠但宽屏):
@media (min-width: 1200px) and (horizontal-viewport-segments: 1) { :root { --sidebar-span: 960px; } } - 侧边栏样式中用:
flex-basis: var(--sidebar-span); min-width: 0; overflow: hidden; transition: flex-basis 0.25s ease; - 禁止对变量做 calc 运算,例如
calc(var(--sidebar-span) - 80px),部分浏览器在分段切换时不会重计算该表达式
JS 监听必须防抖 + 校验 visualViewport
CSS 媒体查询只响应静态状态,但折叠过程存在半开、动画帧、系统延迟上报等中间态,matchMedia 可能 1 秒触发 5–6 次 change,不处理 UI 会疯狂抖动。
- 监听方式:
const mq = window.matchMedia('(horizontal-viewport-segments: 2)'); - 必须加至少 100ms 防抖,避免重复 layout 触发
- 读取宽度应优先用
visualViewport.width而非window.innerWidth,后者在折叠动画中可能滞后或返回错误值 - 不要用
window.onresize替代matchMedia,resize 事件无法感知物理分屏变化
最易被忽略的是:双栏布局不能靠 document.body.clientWidth * 2 算“总宽”,它只是单侧渲染宽度;真正稳定的方案是用 grid-template-columns: 1fr 1fr 或固定列宽配合 flex-basis + min-width: 0 组合,才能同时保可访问性、动画和键盘导航流。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











