应使用@media (horizontal-viewport-segments: 2)或@media (vertical-viewport-segments: 2)配合@supports检测物理分屏,Chrome/Edge 119+支持,Safari/Firefox不支持,需降级并防抖JS监听visualViewport.width。

别用 @media (min-width: 768px) 或 @media (orientation: landscape) 做折叠屏适配——它们根本分不清 Z Fold 展开态和 iPad 横屏,也识别不了铰链物理分割。真正能区分“是否被切开”的,是 horizontal-viewport-segments 和 vertical-viewport-segments,但必须配合 @supports、降级逻辑和防抖 JS 才能落地。
怎么写 @supports + horizontal-viewport-segments 才不白写
Chrome/Edge 119+ 支持,Safari/Firefox 当前完全忽略整条规则,所以不能只靠它生效。
- 必须写成
@supports (horizontal-viewport-segments: 2),不能加括号外的条件,也不能嵌套在@media里 - 匹配时
document.body.clientWidth返回的是单侧宽度(约 375–420px),不是总宽;别拿它算双栏总尺寸 - 降级必须显式:默认按单视口写(比如
.sidebar { display: none; }),只在@supports块内激活双栏逻辑 - 变量统一用
--fold-state: horizontal,避免多个@supports块互相覆盖
vertical-viewport-segments: 2 的实际使用场景
这不是 orientation 的替代品,而是专为翻盖式设备设计的物理分割检测——Z Flip、Pocket 系列展开后,屏幕被水平铰链切成上下两块。
- 只能写
vertical-viewport-segments: 2,写1或>1都不匹配 - 典型布局是顶部工具栏占
50vh、底部内容区占50vh;别用height: 50%,父容器高度可能未定义 - 它和
horizontal-viewport-segments: 2互斥,同一时间最多一个为真 - 不要混用已废弃的
screen-spanning,Chromium 已移除支持,真机上基本不触发
SCSS 里怎么封装折叠态断点逻辑
不能把 horizontal-viewport-segments: 2 直接塞进 @mixin respond-to() —— 它不是断点值,而是媒体特性检测,得单独处理。
立即学习“前端免费学习笔记(深入)”;
- 定义两个语义化混合宏:
@mixin fold-horizontal()和@mixin fold-vertical(),内部直接写@supports块 - 所有折叠相关样式(如 sidebar 跨屏跨度、导航栏分栏)都只在这两个宏里写,避免散落
- 在
:root注入--sidebar-span: 240px这类变量,JS 可读可改,CSS 里用flex-basis: var(--sidebar-span) - 别在混合宏里做
calc(var(--sidebar-span) - 80px)运算——Chrome 119+ 在媒体查询切换时不重算该表达式
为什么 JS 监听 matchMedia 必须加防抖且读 visualViewport.width
折叠动画中 resize 事件严重节流(Pixel Fold 上常只触发 1 次),而 matchMedia 虽能捕获状态帧,但不加控制会疯狂重排。
- 监听必须在脚本加载时立即执行,不能等
DOMContentLoaded—— 折叠状态可能在 DOM 构建前就已变化 - 回调里用
requestAnimationFrame批量更新类名或 CSS 变量,别直接操作大量 DOM - 读取宽度必须用
visualViewport.width,window.innerWidth在动画中跳变剧烈,不可靠 - UA 检测仅作辅助:
navigator.userAgent.includes('Fold')可用于 fallback,但不能作为唯一判断依据
最易被忽略的点是:折叠态下 display: none 会让元素彻底退出可访问树,width: 0 会破坏 flex 流;稳妥做法是组合 flex-basis、min-width: 0 和 overflow: hidden,只对基础跨度做动画。


















