随着全面屏的发展的无论是苹果手机还是安卓手机都会存在着:
- 底部活动条(Home 键)
- 顶部传感器(刘海屏、水滴屏、挖孔屏等)
- 圆角边框
都给页面布局产生了巨大的影响。
在做移动端开发时建议使用 “微信开发者工具”,比起浏览器的移动端模拟,更能发现在全面屏下出现的布局问题。
为了解决这个问题,W3C 推出新的 CSS 样式属性:
safe-area-inset-top //安全区域距离顶部边界的距离
safe-area-inset-bottom //安全距离底部边界的距离
safe-area-inset-left //安全区域距离左边边界的距离
safe-area-inset-right //安全区域距离右边边界的距离
同时我们在 Can I use 上查看其适配环境:
可得知在 iOS 环境中只支持 iOS11.0 以上的版本
iOS11.0-11.2 中使用 “constant()” ,如:
constant(safe-area-inset-top)
iOS11.3 以上使用 “env()” ,如:
env(safe-area-inset-top)
而 Android 则是在 5-6.x 版本中支持,使用的是 “env()”
env(safe-area-inset-top)
当然对于一些不支持的环境只能使用取巧的方式做降级处理,比如为顶部部预留出安全空间,我们可以假设顶部刘海占位都在 40px 以下:
//表示当不支持括号内的属性时
@supports not(constant(safe-area-inset-top)){
page{
padding-top: 40px; //一般浏览器下尺寸单位
/* padding-top: 40rpx */ //微信小程序支持的尺寸单位
}
}
通常我们为了兼容基本都会有这样的写法:
padding-top: 40px;
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
为了方便这里提供 sass 的 @mixin 函数:
@mixin x-padding-top($val:0px) {
padding-top: #{$val * 2};
padding-top: calc(#{$val} + constant(safe-area-inset-top));
padding-top: calc(#{$val} + env(safe-area-inset-top));
}
这里还有一个细节,根据苹果官方文档中的《Designing Websites for iPhone X》说明了,只有在使用了元信息辅助标签的扩展下才可以更好的使用:
The default value of viewport-fit is auto, which results in the automatic insetting behavior seen above. In order to disable that behavior and cause the page to lay out to the full size of the screen, you can set viewport-fit to cover. After doing so, our viewport meta tag now looks like this:
<meta name='viewport' content='initial-scale=1, viewport-fit=cover'>
initial-scale=1
:可视区域不缩放;
cover
:网页内容完全覆盖可视窗口;
布局建议
在移动端我们通常都是头部尾部固定,中间区域自适应滚动。
Dom 结构:
<body>
<head></head>
<main></main>
<footer></footer>
<body>
CSS:
<style>
body {
display: flex; // 利用flex布局
flex-flow: column;
min-height: 100vh;
overflow: hidden;
}
head,
main,
footer {
padding: 0 40px 0 30px;
padding: 0 constant(safe-area-inset-right) 0 constant(safe-area-inset-left);
padding: 0 constant(safe-area-inset-right) 0 constant(safe-area-inset-left);
}
head {
padding-top: 40px;
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
}
main {
flex: 1; //撑开中间内部部分
overflow: auto;
max-height: 60vh; //固定好中间内容的最大高度即可以区域滚动
}
footer {
padding-bottom: 20px;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
</style>
这样布局不用规定 head 与 footer 的高度,可以自适应中间区域的内容并且不影响其背景颜色的覆盖,如果想中间区域尽量多占位可以利用计算属性:
calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - ${head.height} - ${footer.height})
同时支持横屏适配,对于脱离文档流的定位也可以利用 safe-area-inset-*
属性精确定位数值。