根本原因是微信小程序video全屏调用原生播放器,渲染层脱离webview,导致dom与视频层错位、缩放失准及orientation残留;需通过@fullscreenchange事件精准控制tabbar、viewport、body样式及自定义导航栏重绘。

小程序中 video 全屏后显示错位,根本原因不是样式没写对,而是微信原生全屏层脱离 WebView 渲染上下文,导致页面 DOM 与视频层错位、缩放失准、返回后 orientation 残留。H5 和 App 端表现不同,但小程序(尤其 iOS)错位最顽固。
为什么小程序 video 全屏后会错位
微信小程序的 <video></video> 全屏是调用原生播放器(iOS AVPlayer / Android ExoPlayer),它会把视频渲染到独立 Surface 上,完全绕过 WebView 的 CSS 布局流。此时:
- 页面 DOM 仍按竖屏尺寸计算,但视频层已横屏拉伸,视觉上“偏移”或“放大错位”
- 退出全屏时,微信不自动重置
window.orientation或 viewport 缩放,导致后续滚动/定位异常 - tabBar、自定义导航栏等固定元素可能被卡在错误坐标,尤其在 iOS 微信 8.0.50+ 中高频复现
-
cover-view在全屏状态下直接不渲染——这不是 bug,是设计限制
@fullscreenchange 事件必须监听且立即响应
别依赖 document.fullscreenElement 或 window.orientation,它们在小程序里基本不可靠。唯一可信的是组件级事件:
- 必须给
<video></video>加id属性,否则uni.createVideoContext()拿不到实例 - 绑定
@fullscreenchange,并在回调里立刻同步状态:isFullscreen: e.detail.fullScreen - 进入全屏时,隐藏 tabbar:
uni.hideTabBar({ animation: false });退出时显式恢复:uni.showTabBar() - iOS 微信下,用户按物理返回键退出全屏也会触发该事件,必须处理,否则 tabbar 卡住
退出全屏后强制重置 viewport 和 body 尺寸
错位常因 viewport 缩放残留或 body 高度未重绘。不能只改容器,要动根节点:
- 退出全屏后执行:
document.body.style.height = '100vh'; document.body.style.overflow = 'auto'; - 加微延迟再重设:
this.$nextTick(() => { uni.setNavigationBarColor({ backgroundColor: '#ffffff' }); }),避免 iOS 下导航栏颜色残留 - 若用了自定义导航栏(
navigationStyle: custom),退出全屏后需手动重绘:this.$forceUpdate()或触发一次空setData - 真机测试时关闭“自动旋转”开关,否则系统 orientation 变化会干扰微信自己的全屏逻辑
cover-view 失效时的替代方案
cover-view 在全屏期间彻底失效,强行 v-if 切换也无效。想盖住视频控件,只有两个实际可行路径:
- 用
cover-image+cover-view组合做静态按钮(如返回图标),仅限轻量 UI,且必须放在<video></video>同级、页面最外层,不能嵌套在scroll-view内 - 改用
subNVue:在pages.json中配置"subNVues": [{ "id": "video-overlay", "path": "subNVue/video-overlay.nvue", "position": "dock", "type": "popup" }],通过uni.postMessage同步全屏状态,zIndex 设为9999才能压住原生层
错位问题本质是渲染管线割裂,任何纯 CSS 修复(比如 transform、fixed 定位)在小程序里都只是临时掩盖,真正稳定的做法是接受原生层不可控,转而用生命周期事件精准干预 DOM 和 native 状态。真机调试比模拟器重要十倍,iOS 微信和安卓微信行为差异极大,不能共用一套逻辑。











