记一次愚蠢的 issue (css env)

去年 11 月份中旬,随着有赞 Vant Weapp 库 1.0 版本的正式发布,咱们的小程序也是当即跟随官方的脚步,着手把依赖库升级了一下。可是却发现 Vant Weapp 对于苹果的底边适配却在微信开发者工具中消失了。在不了解 css env 实际做用和开发工具适配的的状况下,就鲁莽的发了一个 issue,在此也记录一下,以便于从此查阅与学习。css

safe-area

事实上,由于我的以前工做的重心在了 js 与 pc 上,对 css 以及移动端有所忽略,才会对这个安全区域没有更多的学习以及理解。html

面对新式手机的刘海以及胡子,在开发移动端的小伙伴们不得不对手机型号作适配,若是当前使用的界面是整个屏幕,就会发生当前的显示被遮挡的问题。固然,其实对于小程序来讲,绝大状况下彻底不用考虑上面的刘海,一方面是由于当前的小程序的 navigationBar 作到了适配的功能,不须要考虑头部的问题。从另外一方面来讲,小程序没有特别的需求下也不须要横屏展现。可是对于底部的胡子,咱们须要留给其 34px 的高度。在 1.0 版本以前,Vant Weapp 的适配是这样的。ios

下面代码相对于源代码有所修改,可是基本逻辑是在组件中获取到当前的手机信息。git

// 缓存数据
let cache = null;

// 获取有关安全区域的数据(有缓存得缓存)
function getSafeArea() {
  return new Promise((resolve, reject) => {
    if (cache != null) {
      resolve(cache);
    } else {
      wx.getSystemInfo({
        success: ({ model, statusBarHeight }) => {
          const deviceType = model.replace(/\s/g, '-');
          const iphoneNew = /iphone-x|iPhone11|iPhone12/i.test(deviceType);
		  
          cache = {
            isIPhoneX: iphoneNew,
            statusBarHeight
          };

          resolve(cache);
        },
        fail: reject
      });
    }
  });
}

// 提供对外的 函数调用
export const safeArea = ({
  safeAreaInsetBottom = true,
  safeAreaInsetTop = false
} = {}) =>
  Behavior({
    properties: {
      safeAreaInsetTop: {
        type: Boolean,
        value: safeAreaInsetTop
      },
      safeAreaInsetBottom: {
        type: Boolean,
        value: safeAreaInsetBottom
      }
    },
    lifetimes: {
      attached(): void {
        getSafeArea().then(({ isIPhoneX, statusBarHeight }) => {
          // 当前 data 中就有了判断数据 
          this.setData({ isIPhoneX, statusBarHeight });
        });
      }
    }
  });
复制代码

Behavior 等同于 Vue 中的 mixin, 提供了 isIPhoneX 这个数据,咱们也把该代码拷贝了出来以便于在业务中使用。具体能够参考 Component 构造器 来方便小程序自己的开发。github

env

咱们为了获得可用空间 safe-area 不得不写了大量的 js 代码来判断当前的手机型号,而后再在 wxml 中经过数据驱动来添加 css。单从代码维护性上来看,为了处理 safe-area, 咱们作了一些非必要的耦合,也增长了代码的复杂度。当前代码也不能处理未来可能会有的更多手机型号。web

因此,浏览器提供了另外的函数 env 来帮助咱们处理这一切,不过在此以前,咱们要经过 meta 来让网页使用整个屏幕。小程序

<meta name='viewport' content='viewport-fit=cover'>
复制代码

刚开始,我拿到这个也是一脸懵逼,不是说要使用安全区域吗,为何在此以前却要平铺整个页面呢?后来查阅资料才知道,若是没有该属性,当前的屏幕就会上面和底部的安全区域呈现出白条,很是的木有用户体验。浏览器

事实上,保留安全区,浏览器已经帮咱们作好了,可是咱们确定不能知足于如上所示的样式。若是让我来出设计的话,我可能就直接把网页分红多分,而后各自写css 样式。可是那群大佬不是这样考虑的,他们直接让你把页面填满,而后再提供变量让你对网页的区域作功课。缓存

viewport-fit 出现的本意是对智能手表进行网页显示的适配,可是却被苹果公司先用在了 iPhone X 上(纵观 css 的历史,就会发现目前咱们在业务中使用的不少功能原来的意图根本不是为了解决当前问题)。安全

在告知了浏览器使用整个屏幕后,咱们就能够结合 env 来作适配了。在不兼容 env() 的浏览器中,会自动忽略规则。

/* 使用 safe-area-inset 来对应 竖屏的 top和 bottom,以及横屏的 left 和 right*/
env(safe-area-inset-top);
env(safe-area-inset-right);
env(safe-area-inset-bottom);
env(safe-area-inset-left);

/* 若是当前浏览器没有提供 safe-area-inset-top,那就回退使用 20px */
env(safe-area-inset-top, 20px);
env(safe-area-inset-right, 1em);
env(safe-area-inset-bottom, 0.5vh);
env(safe-area-inset-left, 1.4rem);

.console {
  padding: 12px;
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}
复制代码

任何一个提案都不是一蹴而就的,在 ios 11 时候,咱们是使用 constant 来控制的,若是为了兼容,咱们就必须使用以下代码:

.console {
  /* iOS 11.0 */
  padding-bottom: constant(safe-area-inset-bottom);
  /* iOS 11.2 */
  padding-bottom: env(safe-area-inset-bottom);
}
复制代码

固然,constant 这个单词我认为是命名上的一种“失误”,它在命名上对应的应该是css var,可是在功能上却并没有此意义。而 env 是更符合当前语义的。我也有理由相信,从此的 env 能够提供更多的变量来辅助开发。

鼓励一下

若是你以为这篇文章不错,但愿能够给与我一些鼓励,在个人 github 博客下帮忙 star 一下。 博客地址

参考文档

Designing Websites for iPhone X

MDN viewport-fit

drafts.csswg.org/css-env-1/#…

css env

兼容iphone x刘海的正确姿式

相关文章
相关标签/搜索