横竖屏适配的实战技巧与避坑指南
先上代码,再讲别的
我最近在搞一个移动端视频播放页,客户非得要求横屏时全屏撑满、竖屏自动缩回去,还得适配各种安卓机和iOS。折腾了两天,踩了不少坑,但最终方案还是稳住了。今天不绕弯子,直接把最核心的实现贴出来,后面再聊细节。
// 监听设备方向变化
window.addEventListener('orientationchange', function () {
setTimeout(() => {
handleOrientation(window.orientation);
}, 100); // 延迟一下,确保尺寸已更新
});
// 初始化
handleOrientation(window.orientation);
function handleOrientation(orientation) {
const isLandscape = orientation === 90 || orientation === -90;
if (isLandscape) {
document.body.classList.add('fullscreen-landscape');
document.documentElement.style.overflow = 'hidden';
} else {
document.body.classList.remove('fullscreen-landscape');
document.documentElement.style.overflow = '';
}
// 触发重绘或通知组件调整
window.dispatchEvent(new Event('resize'));
}
.fullscreen-landscape {
width: 100vw;
height: 100vh;
overflow: hidden;
}
.video-container {
width: 100%;
height: 0;
padding-bottom: 56.25%; /* 16:9 比例 */
position: relative;
background: #000;
}
.video-container iframe,
.video-container video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
}
/* 横屏时撑满屏幕 */
.fullscreen-landscape .video-container {
padding-bottom: 0;
height: 100vh;
width: 100vw;
}
<div class="video-container">
<video src="https://jztheme.com/video/demo.mp4" controls></video>
</div>
上面这套组合拳我在 iOS 和主流安卓机型上都亲测有效。尤其是那个 setTimeout 加 100ms 的延迟,别小看它——这是我在三个不同项目里反复验证出来的最优解。因为 orientationchange 触发时,DOM 尺寸还没来得及更新,直接读 window.innerWidth 可能不准。
这个场景最好用:视频/游戏类页面强制横屏
有些业务就是必须横屏才能看全,比如 H5 游戏、视频播放器、图表报表。这时候你可以更激进一点:
function lockLandscape() {
if (screen.orientation && screen.orientation.lock) {
screen.orientation.lock('landscape').catch(err => {
console.warn('无法锁定横屏:', err);
});
}
}
注意!这玩意儿不是所有浏览器都支持。iOS Safari 到现在还不完全支持 screen.orientation.lock(),所以不能当主力方案依赖。建议只在 Android 上开启,并做好降级处理。我之前在一个教育类项目里用了这个,结果一堆家长投诉“手机转不过来”,最后只能 fallback 到提示用户手动旋转。
纯 CSS 实现?也行,但有局限
如果你只是想做点简单的布局切换,其实可以用 media query 来搞定:
@media (orientation: landscape) {
.content {
flex-direction: row;
font-size: 16px;
}
}
@media (orientation: portrait) {
.content {
flex-direction: column;
font-size: 14px;
}
}
这种方式轻量、无 JS 干预,适合信息展示类页面。但它有个致命问题:不会触发 JS 逻辑更新。比如你有个轮播图,在横屏时想改显示数量,光靠 CSS 是做不到的。所以我现在的做法是 JS + CSS 结合:JS 控制类名切换,CSS 负责样式表现。
踩坑提醒:这三点一定注意
- 安卓 WebView 兼容性差到离谱:很多老版本安卓机根本不触发
orientationchange,或者返回的window.orientation值永远是 0。我的解决方案是加一个 resize 事件兜底:
let lastWidth = window.innerWidth;
window.addEventListener('resize', () => {
const newWidth = window.innerWidth;
if (Math.abs(newWidth - lastWidth) > 50) { // 宽高变化明显
handleOrientation(window.orientation);
lastWidth = newWidth;
}
});
- iOS 输入框弹起会干扰判断:键盘弹出时也会触发 resize,而且 orientation 没变,但 viewport 高度变了。这里一定要加过滤条件,避免误判成横竖屏切换。我现在习惯在处理前先判断是否聚焦了输入框:
if (document.activeElement && ['INPUT', 'TEXTAREA'].includes(document.activeElement.tagName)) {
return; // 忽略键盘引起的 resize
}
- 三星部分机型横屏下状态栏占空间:某些 Galaxy 手机横屏时顶部会有系统 UI 占据高度,导致内容被挤压。解决办法是在 meta 中加上:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
特别是viewport-fit=cover这个属性,能让内容延伸到安全区域外,配合 CSS env() 使用效果更好。
高级技巧:模拟 orientation 值,方便调试
你总不能每次测试都手动转手机吧?Chrome DevTools 虽然可以切设备类型,但有时候也不够灵。我写了个调试工具函数,方便本地快速验证:
// 开发环境注入
function simulateOrientation(angle) {
Object.defineProperty(window, 'orientation', {
value: angle,
writable: true,
configurable: true
});
window.dispatchEvent(new Event('orientationchange'));
}
// 使用时:
// simulateOrientation(90); // 模拟横屏
// simulateOrientation(0); // 模拟竖屏
结合本地 localStorage 开关,甚至可以做个浮动按钮挂在页面角落,点击就切换,极大提升调试效率。这个技巧我已经在多个项目中复用,省了不少时间。
还有一个隐藏问题:页面加载时的初始状态
很多人忘了处理页面刚打开时的方向判断。如果用户一开始就横着拿手机,orientationchange 是不会触发的。所以一定要在初始化时主动调一次:
// 页面加载完成后立即检测当前方向
document.addEventListener('DOMContentLoaded', () => {
handleOrientation(window.orientation);
});
不然就会出现“必须转一圈才正常”的诡异现象,用户体验极差。这个坑我第一次上线时就栽了,线上反馈一堆“刚打开黑屏”,排查半天才发现是没初始化。
拓展思路:不只是布局,还能控制行为
除了视觉层面的适配,其实还可以用横竖屏状态来控制交互逻辑。比如:
- 横屏时启用双指缩放查看大图
- 竖屏时隐藏复杂菜单,只留核心操作按钮
- 横屏自动播放视频,竖屏暂停
这些都可以通过监听方向变化来动态绑定/解绑事件,灵活得很。
总结一下我现在的标准流程
我现在做移动端横竖屏适配,基本按这个套路来:
- HTML 加 viewport-fit=cover
- JS 初始化时检测一次方向
- 监听 orientationchange + resize(兼容安卓)
- 加 setTimeout 等尺寸稳定
- CSS 用类名驱动,JS 只负责状态
- 排除 input 聚焦干扰
- 开发环境加模拟函数
这套组合下来,目前覆盖了我手上所有项目的适配需求,包括一些奇葩的定制 ROM 机型。
以上是我踩坑后的总结,希望对你有帮助。这个技巧的拓展用法还有很多,比如结合 gyroscope API 做更精细的方向感知,后续会继续分享这类博客。有更优的实现方式欢迎评论区交流。

暂无评论