記一次愚蠢的 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劉海的正確姿式

相關文章
相關標籤/搜索