一. 前言:
苹果手机从iphoneX之后,屏幕顶部都有一个齐刘海,iPhoneX 取消了物理按键,改成底部小黑条,如果不做适配,这些地方就会被遮挡,所以本文记录一下齐刘海与底部小黑条的适配方法。
二. 知识点学习
1)viewport-fit
iOS11 新增特性,苹果公司为了适配 iPhoneX 对现有 viewport meta 标签的一个扩展,用于设置网页在可视窗口的布局方式,可设置三个值:
- contain: 可视窗口完全包含网页内容
- cover:网页内容完全覆盖可视窗口
- auto:默认值,跟 contain 表现一致
注意:
网页默认不添加扩展的表现是 viewport-fit=contain,需要适配 iPhoneX 必须设置 viewport-fit=cover,这是适配的关键步骤。
2)env() 和 constant()
iOS11 新增特性,Webkit 的一个 CSS 函数,用于设定安全区域与边界的距离,有四个预定义的变量(单位是px):如果是微信小程序的话,viewport-fit默认是 cover
- safe-area-inset-left:安全区域距离左边边界的距离
- safe-area-inset-right:安全区域距离右边边界的距离
- safe-area-inset-top:安全区域距离顶部边界的距离
- safe-area-inset-bottom:安全区域距离底部边界的距离
注意:
1)当 viewport-fit = contain 时 env() 是不起作用的,必须要配合 viewport-fit = cover 使用。对于不支持env() 的浏览器,浏览器将会忽略它。
需要做向后兼容。
2)env() 跟 constant() 需要同时存在,而且顺序不能换。
//适配底部小黑条
.page_bottom {
padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS<11.2 */
padding-bottom: env(safe-area-inset-bottom); /* 兼容iOS>= 11.2 */
}
三. 适配步骤?
1)设置网页在可视窗口的布局方式
<meta name='viewport' content="width=device-width, viewport-fit=cover" />
2)适配导航栏刘海屏
用的是vant的导航栏组件自带的 safe-area-inset-top 属性,因为van-nav-bar导航栏开启了fixed布局,导致页面下面的所有内容,直接上升到了页面的最顶部,部分内容会被van-nav-bar导航栏遮挡,我没用这个组件自带的placeholder占位,而是在外面又增加了一个class类名为navBarCon的div,给他一个和导航栏一样的高度,设置了 height:50px;
这样就会占位了
//适配导航栏刘海屏,用的是vant的导航栏组件,自带的 safe-area-inset-top 属性
<template>
<div class="root">
<div class="navBarCon">
<van-nav-bar
title="收货地址"
left-arrow
fixed
safe-area-inset-top
@click-left="navBack"
/>
</div>
</div>
</template>
<script>
export default {
data () {
return {}
},
mounted () {}
}
</script>
<style lang="scss" scoped>
::v-deep {
.van-nav-bar .van-icon {
color: #333 !important;
font-weight: 600;
font-size: 20px;
}
.van-nav-bar__title {
color: #333;
font-weight: 600;
}
.van-nav-bar__content {
height: 50px;
}
}
.root {
height: 100vh;
.navBarCon {
height: 50px;
}
}
</style>
对于安卓机这里会有个问题,会没有状态栏的一个区域,就是wifi,时间那一栏 (这是个困扰了一段时间的问题),今天解决了来记录下
大体思路:
判断手机系统是否是Andriod,是的话增加一个padding-top
的样式作为安卓的头部距离;ios的话还是让他自己适配
// 判断手机系统
export const getNavigatorType = () => {
let temp = ''
var u = navigator.userAgent
if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) {
temp = 'Android'
} else {
temp = 'ios'
}
return temp
}
<script>
import { getNavigatorType } from '@/utils/tool.js'
mounted () {
let navigatorType = getNavigatorType()
if (navigatorType === 'Android') {
// 获取文档中的第一个class="van-nav-bar"的元素
document.querySelector('.van-nav-bar').style.paddingTop = '20px'
}
},
</script>
3)适配底部小黑条 fixed 元素的适配
吸底的情况(bottom=0)
<template>
<div class="root">
<div class="page_bottom flexAround">
<div class="amount">
<span>合计:</span>
<span class="red">¥</span>
<span class="total_money red">{{ total_money }}</span>
</div>
<div class="payBtn" @click="confirmOrder">提交订单</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {}
},
mounted () {}
}
</script>
<style lang="scss" scoped>
/* 这个方案需要吸底条必须是有背景色的,因为扩展的部分背景是跟随外容器的,否则出现镂空情况。*/
.page_bottom {
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 45px; /*暂时发现安卓小屏手机安全区为0 && 不带单位的话padding-bottom会失效,写一个兜底, 并写在最上面;f12发现css样式如果都给height设置样式,会依次往下,用最底下的一个样式,如果最下面的没失效,依次往上查找,所以兜底的写在最上面 */
height: calc(45px + constant(safe-area-inset-bottom)); /* 直接扩展高度,因为padding-bottom是内边距 */
height: calc(45px + env(safe-area-inset-bottom)); /* 直接扩展高度 */
background: #fff;
padding: 0 11px 0 20px;
box-sizing: border-box;
padding-bottom: constant(safe-area-inset-bottom); /*兼容 iOS<11.2 */
padding-bottom: env(safe-area-inset-bottom); /* 兼容iOS>= 11.2*/
}
.flexAround {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
四:结语
为了方便维护使用,可以把顶部导航栏封装成一个子组件,在父组件中调用
推荐
fixed元素的适配 bottom=0和非0的情况
适配底部小黑条
yidongduanh5安全区适配
如何解决移动端的安全区域为0的问题