H5移动端强制横屏需CSS+JS联动干预,因浏览器不支持pageOrientation且vh/vw不随旋转交换宽高,@media(orientation:landscape)仅作辅助;最稳定方案是transform:rotate(90deg)并互换宽高、校准transform-origin、翻转touch坐标、动态适配字体与Canvas。

H5端在移动端屏幕旋转时布局错乱,根本原因是浏览器不支持强制横屏,pageOrientation 配置完全无效,必须用 CSS + JS 联动干预视口渲染逻辑,否则必然闪烁、错位、字体失真。
为什么 @media (orientation: landscape) 经常失效
这个媒体查询依赖浏览器对 window.orientation 或 resize 事件的响应,但实际中存在大量兼容性问题:iOS Safari 在某些版本下不触发 orientationchange;安卓 WebView 对 orientation 的上报延迟或缺失;更关键的是,vh/vw 单位始终基于“逻辑视口”,而非旋转后的物理尺寸——比如竖屏时 100vh 是 812px,横屏后它还是 812px(而不是按新宽度重新计算),导致容器高度塌陷或溢出。
- 不要只靠
@media (orientation: landscape)控制布局,它只能作为辅助判断,不能承担主适配逻辑 - 避免在横屏样式里直接写
width: 100vw; height: 100vh;,因为 vw/vh 不随旋转自动交换宽高 - 测试时务必用真机,Chrome DevTools 的 device toolbar 模拟不可靠,尤其 orientation 切换行为
用 transform: rotate(90deg) 强制横屏的实操要点
这是目前 H5 端最稳定可控的方案,核心是把整个 或根容器旋转并重设尺寸,绕过浏览器对 orientation 的弱支持。
- 必须同时设置
width和height互换:横屏时width: 100vh; height: 100vw;,否则内容被裁剪 -
transform-origin必须设为视口中心,例如transform-origin: 50vh 50vw;,否则旋转后偏移严重 - 旋转后 touch 事件坐标会反向,需在业务层手动翻转
clientX/clientY(如游戏或签名场景) - 加
overflow: hidden到html或body,防止旋转后出现滚动条或白边
JS 动态检测宽高比并切换样式的安全时机
直接在 mounted 或 onLaunch 里执行旋转逻辑容易导致闪屏——DOM 渲染完成前样式未生效,用户先看到竖屏再跳变。正确做法是等视口稳定后再应用。
- 首次加载用
setTimeout(() => { applyRotate() }, 0)或requestAnimationFrame延迟到下一帧 - 监听
resize事件,但要防抖(300ms间隔),避免频繁重排 - 判断横竖屏用
document.documentElement.clientWidth > document.documentElement.clientHeight,比window.orientation更可靠 - 在
App.vue的onShow钩子中再次校验,处理从后台切回前台时的方向变化
字体和 rpx/upx 在横屏下的失真问题
uni-app 的 rpx 基于设计稿宽度(通常是 750rpx = 375px),但横屏后设备物理宽度变大,而 rpx 计算仍按原始 viewport 宽度,导致文字突然变小或布局撑开。
- 禁用
rpx在横屏页面,改用vw(如font-size: 4vw;),并配合 JS 动态设置根字体大小 - 若必须用 rpx,可在横屏激活时调用
uni.setStorageSync('isLandscape', true),在全局 mixin 中拦截 rpx 计算逻辑 - 视频、Canvas 等原生元素需单独处理:
uni.getSystemInfo返回的screenWidth/screenHeight是固定方向值,横屏时应手动交换使用
真正难的不是写出旋转代码,而是让旋转后的交互坐标、字体缩放、Canvas 绘制、滚动位置全部同步对齐——这些细节一旦漏掉,用户就会觉得“页面卡了一下”或“点不准”。每个环节都要单独验证,不能假设 CSS 旋转能自动透传所有行为。


















