渴望成为大牛的男人

渴望成为大牛的男人

IphoneX适配正确姿势

写在前面

距离18年9月iphonex发布以来已经快两年了(所以对于iphonex机型的头部刘海(sensor housing)和底部小黑条(Home Indicator)的内容本文不在做过多赘述了),相信还有一些同学为iphonex系列机型如何完美适配在发愁,笔者结合公司移动端h5项目和一些官方文档做了一个总结,希望可以帮到大家。

预备知识

安全区域

大家应该能看懂safe area是安全区域的意思吧?那顾名思义,如下图所示,安全区域就是指的不受头部刘海以及底部小黑条影响的那一部分区域。
IphoneX适配正确姿势-LMLPHP
苹果官网人机交互指南

viewport-fit

viewport-fit是 IOS 11 新增的特性,关于viewport-fit的枚举值介绍如下:

  • contain: 可视窗口完全包含网页内容(左图)
  • cover:网页内容完全覆盖可视窗口(右图)
  • auto:默认值,跟 contain 表现一致

IphoneX适配正确姿势-LMLPHP
IphoneX适配正确姿势-LMLPHP

关于viewport-fit更详细介绍

env() 和 constant()

安全区域位置信息常量值

  • safe-area-inset-top:从视口顶部开始的安全区域插入量(以CSS像素为单位)。
  • safe-area-inset-bottom:从视口底部开始的安全区域插入量(以CSS像素为单位)。
  • safe-area-inset-left:从视口左侧开始的安全区域插入量(以CSS像素为单位)。
  • safe-area-inset-right:从视口右侧开始的安全区域插入量(以CSS像素为单位)。

env() 和 constant()介绍

env() 和 constant()是IOS 11的新增特性,是两个css函数,先来看看这两个函数的兼容性:

IphoneX适配正确姿势-LMLPHP

我们可以看到在IOS 11.0-11.2是支持constant函数的,在11.3往后是废弃了constant函数,取而代之的是env函数。

简单示例

空出底部安全距离

padding-bottom: constant(safe-area-inset-bottom);  // 兼容 11.0 < iOS < 11.2
padding-bottom: env(safe-area-inset-bottom);  // 兼容 iOS >= 11.2

注意点

  • 需要设置viewport-fit=cover,安全区域位置信息才有;
  • 写的时候需要constant和env函数都写上,以达到可以兼容所有IOS 11系统;

小结

需要注意使用安全区域位置信息的前置条件是设置viewport-fit=cover,然后上述所说的信息属于IOS 11新增内容,iphonex出厂系统是大于等于11.0的,所以可以放心大胆的去用来做iphonex的兼容。

正确姿势

看完前面以后,大家的一些奇怪的知识已经具备了,接下来就开始正式进入适配iphonex系列机型环节。当然,看完下面以后我们就会用最完美最简洁的姿势去进行适配了,不要眨眼,go~

前置条件

设置viewport-fit=cover

<meta name="viewport" content="width=device-width,viewport-fit=cover">

需要适配的iphonex系列机型“容器”

我们的移动端h5页面一般无非在四个“容器”中打开:微信、网页、App、小程序。所以我们需要针对这四个“容器”对我们的页面做一些适配以便在iphonex系列机型中完美展现妾身的舞姿。

在微信、小程序、网页中的适配

头部

因为在这些“容器中”,头部都已经由“容器”给我们适配好了(懂王自然懂),所以我们只需要关注底部即可。

底部

姿势:页面整体底部空出安全距离(不同的项目布局方式不同,视情况决定加在哪个地方更加合理(page,basicPage)):

body {
  box-sizing: border-box;
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

在App中的适配

头部

头部兼容我们需要在自己项目的导航头组件下手,思路就是给导航头加上顶部安全距离,避免导航头顶到刘海里面。

  • 判断在ios并且处在app环境中的时候加一个特定的类名,比如:ipx-head-nav
  • 给ipx-head-nav加一个padding-top值空出来顶部安全距离
.ipx-head-nav {
  padding-top: 20px; // iphonex系列机型之前顶部安全距离均为20px
  padding-top: constant(safe-area-inset-top);
  padding-top: env(safe-area-inset-top);
}

padding-top为20px去兼容iphonex以及IOS 11系统之前的机型,constant和env函数去适配iphonex以及IOS 11系统之后的机型。

底部

和在微信、小程序、网页中的底部适配姿势一致,统一姿势。

一些特殊场景的处理

吸底(bottom === 0)的按钮

建议吸底按钮都改为fixed定位,然后我们用这个姿势去适配:

.btn {
  position: fixed;
  bottom: 0; // 当constant和env函数都不支持的时候,这个会生效
  bottom: constant(safe-area-inset-bottom);
  bottom: env(safe-area-inset-bottom);
  &:after {
    content: ' ';
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #ffffff;
    height: constant(safe-area-inset-bottom);
    height: env(safe-area-inset-bottom);
  }
}

因为在iphonex上,按钮bottom为底部安全距离,那和最下面就会有一段镂空的空档,所以还需要把这个空档给补上。

思路:

  1. 按钮bottom值先适配iphonex;
  2. 添加一个新的元素补到空档的位置,高度就是安全距离的高度。

fixed定位的非完全吸底(bottom !== 0)元素,比如“返回顶部”按钮

在这里我们假设有一个需求,一个“返回顶部”的按钮,需要距离底部30px,还需要适配iphonex,那么我们就可以使用下面的姿势:

.back-top-btn {
  bottom: 30px;
  bottom: calc(30px + constant(safe-area-inset-bottom));
  bottom: calc(30px + env(safe-area-inset-bottom));
}

在不支持constant和env函数的系统中,bottom计算出来的值是无效的,bottom: 30px会生效。

小福利

相信大家现在已经掌握了适配iphonex系列机型的正确姿势了,如果你的项目里是使用scss去编写样式的,在这里送大家3个牛逼的姿势秘籍,这么简单的姿势应该一看就能懂是怎么用的,不懂的话可以在评论区留言提问:

// ipx系列底部padding值
@mixin iphonex-padding-bottom($paddingBottom: 0px) {
  padding-bottom: $paddingBottom;
  padding-bottom: calc(#{$paddingBottom} + constant(safe-area-inset-bottom));
  padding-bottom: calc(#{$paddingBottom} + env(safe-area-inset-bottom));
}

// ipx系列fixed定位底部bottom值
@mixin iphonex-fixed-bottom($bottom:0px) {
  bottom: $bottom;
  bottom: calc(#{$bottom} + constant(safe-area-inset-bottom));
  bottom: calc(#{$bottom} + env(safe-area-inset-bottom));
}

// ipx系列fixed定位bottom为0的处理函数
@mixin iphonex-fixed-bottom-zero($backgroundColor: #ffffff) {
  @include iphonex-fixed-bottom();
  &:after {
    content: ' ';
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: $backgroundColor;
    height: constant(safe-area-inset-bottom);
    height: env(safe-area-inset-bottom);
  }
}

写在最后

以上分享的姿势是笔者总结出来的比较通用的解决方案,但方案并不是唯一的,只是希望能给大家提供一种解决思路,让自己的应用更加完美。最后当然是要感谢大家的阅读啦,thank you~

12-21 00:49