铰链区域遮挡需放弃静态定位,改用系统安全边界与容器查询:通过@container hinge-safe定义双列网格留出2px铰链间隙,控件仅置于左右列;监听matchMedia('(display-fold: horizontal)')的change事件防抖更新class,避免DOM高频操作。

铰链区域遮挡导致控件不可见
折叠屏展开后,屏幕中间存在物理铰链(或显示缝),window.innerWidth 和 screen.width 仍返回完整宽度,但实际可绘制区域被中断。若用传统 flex 或 grid 布局把按钮放在水平中线(如 justify-content: center),它大概率会被铰链遮住——用户点不到,也看不到。
根本问题不是“布局没居中”,而是“居中坐标落在不可用区域”。必须放弃基于像素坐标的静态定位,改用系统提供的安全区域边界。
- Android 12+ 提供
env(safe-area-inset-left)/env(safe-area-inset-right),但**铰链不在左右,而在中间**,这些 CSS 环境变量无效 - 真正可用的是
display: fold媒体查询 +@media (dynamic-range: high)组合判断,但目前仅 Chrome Beta(v125+)和 Samsung One UI 6.1+ 支持 - 最稳妥的 fallback 是监听
window.matchMedia('(display-mode: standalone)')+window.matchMedia('(min-aspect-ratio: 4/3)'),再结合window.innerHeight > 800排除小屏竖屏干扰
用 CSS @container 配合 hinge-safe 区域类名做条件渲染
现代方案不靠 JS 计算偏移,而靠容器查询 + 布局约束。关键不是“避开铰链”,而是“让容器自己知道它是否跨铰链”。
步骤很简单:
立即学习“前端免费学习笔记(深入)”;
- 给最外层
<main>加container-type: inline-size,并设container-name: hinge-safe - 写媒体查询:
@container hinge-safe (min-width: 720px) and (aspect-ratio >= 2/1)—— 这个条件只在展开态、且宽度足够时命中 - 在此查询内,用
grid-template-columns: 1fr 2px 1fr显式留出 2px 铰链间隙,中间列设background: transparent且pointer-events: none - 所有交互控件只放在左右两列,绝不跨中线
示例片段:
main {
container-type: inline-size;
container-name: hinge-safe;
}
@container hinge-safe (min-width: 720px) and (aspect-ratio >= 2/1) {
.content-grid {
display: grid;
grid-template-columns: 1fr 2px 1fr;
}
.content-grid > *:nth-child(2) {
grid-column: 1;
}
.content-grid > *:nth-child(3) {
grid-column: 3;
}
}JS 动态注入 hinge-aware class 的时机陷阱
很多项目在 DOMContentLoaded 里读 window.innerWidth 并加 class,结果折叠动画刚启动时 class 就错了——因为 resize 事件在动画中高频触发,而铰链状态切换是离散事件。
正确做法是监听 matchMedia 的 change,而非 resize:
- 用
const hingeQuery = window.matchMedia('(display-fold: horizontal)')—— 注意不是single-fold-horizontal,后者是旧版废弃语法 - 必须在
hingeQuery.addEventListener('change', handler)中更新 class,且 handler 内要防抖(setTimeout延迟 100ms,等动画帧结束) - 首次检查不能只看
hingeQuery.matches,要结合window.visualViewport?.width,因为某些设备冷启动时 media query 缓存未就绪 - 别在 handler 里直接操作 DOM 样式,统一走
document.body.classList.toggle('hinge-open', matches),让 CSS 控制一切
真机调试时 layout shift 被误判为性能问题
Chrome DevTools 的 Performance 面板看到大量 Layout 阶段耗时,容易以为是 CSS 写错了。其实折叠动画本身就会触发连续 layout,这是正常行为。
真正要盯的是:布局重构是否在 300ms 内完成。方法是加一个简单的打点:
const start = performance.now();
hingeQuery.addEventListener('change', () => {
// 更新 class 后强制重排
document.body.offsetHeight;
console.log('hinge layout time:', performance.now() - start);
});如果超过 300ms,问题通常出在:用了 document.querySelector 遍历深层节点、CSS 中写了 @keyframes 动画影响 layout、或在 change 回调里调用了 getBoundingClientRect()。
铰链适配的复杂点不在“怎么写”,而在于“什么时候写”——状态切换是瞬时的,但视觉反馈需要缓冲;布局计算要快,但不能抢在浏览器合成帧之前。这点很容易被忽略。



















