你以为折叠屏适配只能靠orientation判断?今天四个CSS媒体查询把这件事彻底原生化了

写过移动端适配的人都踩过这个坑——页面在折叠屏上打开,内容刚好被铰链切成两半,字刚好断在折缝里。你以为这是硬件问题,其实是你的 CSS 根本没拿到折叠屏的状态信息,只能靠 orientation: landscape 猜,猜对了算运气好。

这件事今天被 Viewport Segments API 彻底原生化了。

旧方案为什么不行

以前做响应式,你用的是这套:

/* 只能判断横屏竖屏,跟折叠状态毫无关系 */
@media (orientation: landscape) {
  .layout { flex-direction: row; }
}

问题是:一部折叠屏展开成平板形态,orientation 仍然是 portrait,但你实际上有了左右两个屏幕区域。这套逻辑在 Z Fold 半开状态、横折展开状态、分屏多窗口状态下全部失效。

你只能靠 JavaScript 监听 resize,然后手动算 window.innerWidth 落在哪个区间,再动态计算每个区域该多宽。这套方案脆弱到换一个机型就要重调。

四个媒体查询,把折叠状态说清楚了

Chrome 138/Edge 138 稳定支持 Viewport Segments API,给了你两个正交的维度:

/* 水平方向被分割成几块(竖折手机展开 → 左右两个屏) */
@media (horizontal-viewport-segments: 2) { }

/* 竖直方向被分割成几块(横折平板展开 → 上下两个屏) */
@media (vertical-viewport-segments: 2) { }

这两个值是独立的,可以组合:

/* 竖折手机完全展开:左右两块屏 */
@media (horizontal-viewport-segments: 2) and (vertical-viewport-segments: 1) {
  .layout { display: flex; }
}

/* 横折平板完全展开:上下两块屏 */
@media (horizontal-viewport-segments: 1) and (vertical-viewport-segments: 2) {
  .layout { flex-direction: column; }
}

这才是真正的「硬件感知」——它告诉你的是物理屏幕怎么被分割,而不是屏幕旋转了几度。

拿到分割尺寸:env() 变量

光知道有几块屏还不够,你还得知道每块有多宽、有多高、铰链占多少空间。六个环境变量把这件事说清楚了:

.wrapper {
  display: flex;
  height: 100%;
}

@media (horizontal-viewport-segments: 2) {
  .list-view {
    /* 左侧第一块屏的宽度 */
    width: env(viewport-segment-width 0 0);
  }

  .fold {
    /* 铰链宽度:右侧起点 - 左侧终点 */
    width: calc(
      env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0)
    );
    background-color: black;
  }

  .detail-view {
    /* 右侧第二块屏的宽度 */
    width: env(viewport-segment-width 1 0);
  }
}

第一个数字是 segment 索引(0 = 第一块,1 = 第二块),第二个是轴向(0 = 主轴,1 = 副轴)。你可以精确算出铰链的宽度,然后把内容对齐到真实屏幕边界,而不是对齐到虚拟的屏幕中线。

完整落地例子

以一个常见的邮件列表场景为例:

<div class="wrapper">
  <aside class="list-view"></aside>
  <div class="fold-gutter"></div>
  <main class="detail-view"></main>
</div>
/* 普通手机:单栏 */
.wrapper { display: flex; flex-direction: column; }

/* 竖折屏展开:列表在左,详情在右,铰链有独立间距 */
@media (horizontal-viewport-segments: 2) {
  .wrapper { flex-direction: row; }
  .list-view {
    width: env(viewport-segment-width 0 0);
  }
  .fold-gutter {
    width: calc(
      env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0)
    );
  }
  .detail-view {
    width: env(viewport-segment-width 1 0);
  }
}

整个方案不需要一行 JavaScript。CSS 自己读到了硬件状态,布局自动适配。

浏览器支持现状

特性 Chrome/Edge Firefox Safari
horizontal-viewport-segments 138+
vertical-viewport-segments 138+
env(viewport-segment-*) 138+

Chrome 和 Edge 全面支持,Firefox 和 Safari 还未跟进。生产环境建议渐进增强:

/* 默认:单栏布局,所有浏览器都正常工作 */
.layout { display: flex; flex-direction: column; }

/* 增强:只有支持的浏览器才响应折叠状态 */
@supports (horizontal-viewport-segments: 2) {
  @media (horizontal-viewport-segments: 2) {
    .layout { flex-direction: row; }
    /* ... */
  }
}

不支持的浏览器继续走单栏,不影响功能。

下一步

现在去 Chrome DevTools 打开设备模拟,选择「Samsung Galaxy Z Fold」或「Surface Duo」,切换到「Spanned」模式,看你的页面布局有没有被铰链影响。如果有,这套 API 就是你等了很久的答案。

官方 Demo 和规范在 Chrome Foldable APIs 页面可以找到,MDN 上有完整的 env() 变量对照表。

评论区

0 条评论

登录后可评论。

阿跨·跨端开发 10 阅读