微信小程序中安全区域计算和适配
前言
自从iphoneX问世之后,因为iphoneX、iphoneXR和后续全面屏手机设备,因为物理Home键被底部小黑条代替了,这时候很多前端小伙伴在开发的过程都会遇到 “全面屏”和“非全面屏”的兼容性问题,普遍问题就是底部按钮或者选项卡与底部黑线重叠
解释
根据官方解释:
安全区域指的是一个可视窗口范围,处于安全区域的内容不受圆角(corners)、齐刘海(sensor housing)、小黑条(Home Indicator)的影响。
具体区域如图展示
[图片]
适配方案
当前有效的解决方式有几种
使用已知底部小黑条高度34px/68rpx来适配
使用苹果官方推出的css函数env()、constant()适配
使用微信官方API,getSystemInfo()中的safeArea对象进行适配
使用已知底部小黑条高度34px/68rpx来适配
这种方式是根据实践得出,通过物理方式测出iPhone底部的小黑条(Home Indicator)高度是34px,实际在开发者工具选中真机获取到高度也是34px,所以直接根据该值,设置margin-bottom、padding-bottom、height也能实现。同时这样做要有一个前提,需要判断当前机型是需要适配安全区域的机型。
但是这种方案相对来说是不推荐使用的。比较是一个比较古老原始的方案
使用苹果官方推出的css函数env()、constant()适配
这种方案是苹果官方推荐使用env(),constant()来适配,开发者不需要管数值具体是多少。
env和constant是IOS11新增特性,有4个预定义变量:
safe-area-inset-left:安全区域距离左边边界的距离
safe-area-inset-right:安全区域距离右边边界的距离
safe-area-inset-top:安全区域距离顶部边界的距离
safe-area-inset-bottom :安全距离底部边界的距离
具体用法如下:
Tips: constant和env不能调换位置
[代码] padding-bottom: constant(safe-area-inset-bottom); /*兼容 IOS<11.2*/
padding-bottom: env(safe-area-inset-bottom); /*兼容 IOS>11.2*/
[代码]
其实利用这个能解决大部分的适配场景了,但是有时候开发需要自定义头部信息,这时候就没办法使用css来解决了
使用微信官方API,getSystemInfo()中的safeArea对象进行适配
通过 wx.getSystemInfo获取到各种安全区域信息,解析出具体的设备类型,通过设备类型做宽高自适应,话不多说,直接上代码
代码实现
[代码] const res = wx.getSystemInfoSync()
const result = {
...res,
bottomSafeHeight: 0,
isIphoneX: false,
isMi: false,
isIphone: false,
isIpad: false,
isIOS: false,
isHeightPhone: false,
}
const modelmes = result.model
const system = result.system
// 判断设备型号
if (modelmes.search('iPhone X') != -1 || modelmes.search('iPhone 11') != -1) {
result.isIphoneX = true;
}
if (modelmes.search('MI') != -1) {
result.isMi = true;
}
if (modelmes.search('iPhone') != -1) {
result.isIphone = true;
}
if (modelmes.search('iPad') > -1) {
result.isIpad = true;
}
let screenWidth = result.screenWidth
let screenHeight = result.screenHeight
// 宽高比自适应
screenWidth = Math.min(screenWidth, screenHeight)
screenHeight = Math.max(screenWidth, screenHeight)
const ipadDiff = Math.abs(screenHeight / screenWidth - 1.33333)
if (ipadDiff < 0.01) {
result.isIpad = true
}
if (result.isIphone || system.indexOf('iOS') > -1) {
result.isIOS = true
}
const myCanvasWidth = (640 / 375) * result.screenWidth
const myCanvasHeight = (1000 / 667) * result.screenHeight
const scale = myCanvasWidth / myCanvasHeight
if (scale < 0.64) {
result.isHeightPhone = true
}
result.navHeight = result.statusBarHeight + 46
result.pageWidth = result.windowWidth
result.pageHeight = result.windowHeight - result.navHeight
if (!result.isIOS) {
result.bottomSafeHeight = 0
}
const capsuleInfo = wx.getMenuButtonBoundingClientRect()
// 胶囊热区 = 胶囊和状态栏之间的留白 * 2 (保持胶囊和状态栏上下留白一致) * 2(设计上为了更好看) + 胶囊高度
const navbarHeight = (capsuleInfo.top - result.statusBarHeight) * 4 + capsuleInfo.height
// 写入胶囊数据
result.capsuleInfo = capsuleInfo;
// 安全区域
const safeArea = result.safeArea
// 可视区域高度 - 适配横竖屏场景
const screenHeight = Math.max(result.screenHeight, result.screenWidth)
const height = Math.max(safeArea.height, safeArea.width)
// 状态栏高度
const statusBarHeight = result.statusBarHeight
// 获取底部安全区域高度(全面屏手机)
if (safeArea && height && screenHeight) {
result.bottomSafeHeight = screenHeight - height - statusBarHeight
if (result.bottomSafeHeight < 0) {
result.bottomSafeHeight = 0
}
}
// 设置header高度
result.headerHeight = statusBarHeight + navbarHeight
// 导航栏高度
result.navbarHeight = navbarHeight
[代码]