折叠屏设备检测应使用 window.matchmedia 而非 navigator.useragent;需结合 hinge 媒体查询、宽度/横纵比、visualviewport.width 等多维度判断,避免依赖 ua 字符串或 screen 尺寸。

折叠屏设备检测靠 window.matchMedia,别信 navigator.userAgent
折叠屏不是单纯“大屏”,而是有物理铰链、可动态切换展开/折叠状态的设备。很多开发者一上来就 parse navigator.userAgent 里有没有 “Fold” 或 “SamsungBrowser”,结果在 Chrome 120+、Edge 122+ 下失效——UA 字符串已被逐步弱化,且华为 Mate X 系列、Pixel Fold 的 UA 差异极大。
真正可靠的判断方式是监听折叠状态媒体查询:
const foldMedia = window.matchMedia('(display-mode: standalone) and (min-width: 720px)');
// 更精准:检测 hinge 区域(仅 Chromium 119+ 支持)
const hingeMedia = window.matchMedia('(horizontal-stretch: 1)'); // 展开态
const foldMediaV2 = window.matchMedia('(dynamic-range: high) and (color-gamut: p3)'); // 辅助判断高端折叠屏
注意:hinge 相关媒体特性仍属实验性,生产环境必须 fallback 到宽度 + 横纵比组合判断:
-
window.innerWidth > 720且window.innerHeight / window.innerWidth → 大概率为展开态横屏 window.innerWidth → 默认按折叠态小屏处理- 始终监听
resize和orientationchange,因为用户可能中途展开/合拢
Flex/Grid 布局在折叠态下会错乱,必须用 container queries 替代纯 viewport 断点
传统 @media (min-width: 768px) 在折叠屏上失效:展开时 viewport 宽度可能达 1200px,但铰链区域把屏幕切成两块,左侧 600px 内容区实际可用宽度只有 520px(扣掉 hinge 阴影和系统 UI)。
直接后果是:导航栏突然变成三列、卡片 grid 被强行拉伸变形、文字溢出容器。
解决方案不是调大断点值,而是改用容器级响应:
.sidebar { container-type: inline-size; }
@container (min-width: 500px) {
.sidebar-nav { display: flex; }
}
@container (max-width: 499px) {
.sidebar-nav { display: block; }
}
关键点:
- 必须给容器加
container-name(如container: sidebar / inline-size),否则@container不生效 - Chrome 116+、Firefox 119+ 支持,Safari 17.4+ 才开始支持,iOS 17.4 用户占比已超 65%,可放心用
- 避免对
body或main这类全屏容器用 container query——它没意义,要作用在具体功能模块的 wrapper 上
折叠态触发 resize 事件太频繁,防抖逻辑必须基于 screen.width 而非 window.innerWidth
用户缓慢展开折叠屏时,window.innerWidth 可能在 500→505→510→…→800 之间连续触发 20+ 次 resize,导致 React 组件反复 re-render、Canvas 重绘卡顿、第三方地图 SDK 崩溃。
根本原因是:折叠过程中的 viewport 尺寸是渐变的,但真正影响布局的是「当前有效显示区域」,即 screen.width(物理像素宽度)和 screen.availWidth(可用宽度)。
实操建议:
- 监听
window.visualViewport?.onresize(比 window.resize 更精准,排除地址栏缩放干扰) - 判断依据优先级:
screen.availWidth>screen.width>window.innerWidth - 防抖阈值设为 300ms 起步,但若检测到
screen.availWidth变化 ≥ 50px,立即执行,不等防抖结束
双屏应用模式(如 Samsung DeX、华为多窗)下,window.screen 返回的是虚拟屏尺寸
当用户开启 DeX 模式或分屏时,window.screen.width 可能返回 1920,但实际渲染区域只有 960px(另一半被其他 App 占用)。此时靠 screen 判断折叠态会误判为“桌面模式”。
正确做法是结合 document.documentElement.clientWidth 和 window.visualViewport?.width:
-
visualViewport.width始终反映当前页面实际渲染宽度(含缩放) - 若
visualViewport.width ,大概率处于分屏/多窗模式 - Android 14+ 新增
navigator.windowControlsOverlayAPI,可检测是否启用刘海/挖孔/折叠屏专属 UI 控件
折叠屏适配最麻烦的从来不是写多少 CSS,而是得同时应付硬件状态、系统模式、浏览器实现差异这三层变量。铰链位置没法用 CSS 模拟,只能靠真实设备反复测 —— 没有真机,所有 media query 都是纸上谈兵。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











