uni.getsysteminfosync()是最直接可靠的跨端获取系统信息方式,能一次性获得windowwidth、windowheight、screenwidth、screenheight和pixelratio等关键字段,避免异步风险与dom api不一致问题。

uni.getSystemInfoSync() 是最直接可靠的获取方式
不需要 Promise 或回调,调用即得完整信息,适合在 onLoad、onShow 甚至 data 初始化时安全使用。异步版 uni.getSystemInfo 容易因未等 success 就取值,导致 undefined。
关键字段一次性拿到:
-
windowWidth和windowHeight:当前可渲染区域的逻辑宽高(单位 px),已扣除状态栏、默认导航栏、软键盘弹出影响,**做布局适配应优先用这两个值** -
screenWidth和screenHeight:整块屏幕的物理像素数,固定不变(如 iPhone 14 Pro 是1170×2532),仅用于判断设备能力或 Canvas 底层绘制 -
pixelRatio:就是 DPR,物理像素与 CSS 像素之比(如3表示 1px 对应 3×3 物理像素),直接影响图片加载、Canvas 渲染、字体清晰度
示例:
const sys = uni.getSystemInfoSync(); console.log(sys.windowWidth); // 如 375(逻辑宽度) console.log(sys.pixelRatio); // 如 3 console.log(sys.screenWidth); // 如 1170(物理宽度)
为什么不能只用 window.innerWidth?
在 H5 端它看似能用,但跨端一致性差——小程序和 App 端根本没 window 对象,且它不剔除地址栏、滚动条等干扰;更关键的是,它返回的是浏览器视口尺寸,和 uni-app 的渲染逻辑区域(windowWidth)不是一回事。
常见错误现象:
- 在 App 端写
window.innerWidth报Cannot read property 'innerWidth' of undefined - H5 上值为
360,但uni.getSystemInfoSync().windowWidth是375,导致 rpx 换算错位 - 横屏切换后
window.innerWidth更新了,但 uni-app 的样式系统仍按竖屏windowWidth计算,出现布局撕裂
结论:跨端项目必须统一走 uni.getSystemInfoSync(),不要混用原生 DOM API。
Canvas 高清绘制必须乘 DPR,但别在 style 上设
很多人把 canvas 的 width/height 写成固定值(如 375 × 600),再用 CSS 缩放,结果图一画就糊——因为 canvas 的 width/height 属性控制的是**绘图缓冲区的物理像素数**,不是显示大小。
正确做法(三步缺一不可):
- 用
uni.createSelectorQuery()拿到 canvas 节点对象(不能用ref直接取,时机不对) - 设节点的
node.width = windowWidth * pixelRatio、node.height = windowHeight * pixelRatio(注意是 node 属性,不是style.width) - 获取 ctx 后立刻执行
ctx.scale(pixelRatio, pixelRatio),让后续所有坐标、字号、线宽都按逻辑尺寸写
漏掉 scale 或写反顺序(先 draw 再 scale),都会导致坐标系错位、文字缩放异常。
安全区和导航栏高度要单独处理,别靠 DPR 推算
pixelRatio 只管像素密度,和界面可用空间无关。状态栏、胶囊按钮、底部安全区这些,得靠别的 API:
-
statusBarHeight:从uni.getSystemInfoSync()直接取,iOS 稳定,Android 各厂差异大 -
uni.getMenuButtonBoundingClientRect():拿右上角胶囊的top、height,计算自定义导航栏高度(top + height常是总高度) -
safeAreaInsets:iOS 11+ / Android 10+ 支持,但模拟器常返回空或不准,真机调试才可靠
容易被忽略的一点:windowHeight 已自动扣除了状态栏和默认导航栏,但如果你用了自定义导航栏,就得手动减去它的高度,否则内容会上顶被遮挡——这个减法和 DPR 完全无关,别试图用 DPR 去“估算”导航栏像素。











