@media (orientation: landscape) 无法可靠响应横竖屏切换,因它仅静态比对宽高且iOS Safari常忽略动态变化;应改用screen.orientation API配合change事件,并手动初始化+防抖,CSS通过动态添加body类名实现精准控制。

@media (orientation: landscape) 不能用来“锁定”布局,它只在页面加载或首次旋转时匹配一次,之后不再更新。iOS Safari 甚至完全忽略动态变化,Android WebView 也常返回初始值——你写的样式可能永远不生效。
为什么 @media (orientation: landscape) 经常不触发
它不是监听物理旋转,而是静态比对 window.innerWidth >= window.innerHeight,且只在浏览器完成 reflow 后延迟判断。常见失效场景包括:
- iOS Safari 地址栏未隐藏,横屏时
innerHeight突然变大,导致matches仍为false - 折叠屏半展开、macOS Slide Over、Windows Snap 分屏下宽高比“凑巧”不满足条件
-
标签写错(比如缺
width=device-width),整个媒体查询直接失效 - PWA 或 iframe 嵌入时受
Permissions-Policy: screen-orientation限制
真正能响应旋转的 JS 方式:screen.orientation + change 事件
这是目前唯一能读取设备真实物理朝向的可靠 API。但必须注意两个关键点:初始化调用、防抖处理。
- 先检查支持性:
'orientation' in screen—— 不是所有环境都支持(如某些 WebView) -
screen.orientation.type返回portrait-primary/landscape-secondary等,比宽高比更准 - 必须手动执行一次
updateLayout(),否则首屏 class 缺失,样式错乱 -
resize事件不可靠(尤其 iOS),不能只靠它;orientationchange已废弃,不要用
示例逻辑:
if ('orientation' in screen) {
const updateLayout = () => {
document.body.className = screen.orientation.type.startsWith('portrait')
? 'orient-portrait'
: 'orient-landscape';
};
screen.orientation.addEventListener('change', updateLayout);
updateLayout(); // 关键:补初始化
} else {
// 降级 fallback:用 matchMedia('(min-aspect-ratio: 1/1)')
const mq = window.matchMedia('(min-aspect-ratio: 1/1)');
const updateByMq = () => {
document.body.classList.toggle('orient-landscape', mq.matches);
};
mq.addEventListener('change', updateByMq);
updateByMq();
}
如何用 CSS 配合 JS 实现「仅横屏生效」的样式块
别写 @media (orientation: landscape) { ... },改用 JS 动态加 class 到 <body>,再写对应规则:
立即学习“前端免费学习笔记(深入)”;
- 推荐加到
<body>而非<html>,避免影响 :root 变量作用域 - CSS 中用
.orient-landscape .my-module { flex-direction: row; },语义清晰、可维护性强 - 若需精确控制旋转后尺寸,优先用
flex-direction或grid-template-columns重构,而非transform: rotate(90deg)—— 后者不改变文档流,会导致点击区域错位、滚动异常 - 微信内嵌 WebView 对
screen.orientation支持不稳定,建议叠加window.innerHeight > window.innerWidth主动检测兜底


















