關(guān)于 Safari 100vh 的問(wèn)題與解決方案

配圖源自 Freepik

一欠雌、背景

最近在做一個(gè)移動(dòng)端的 H5 項(xiàng)目蹄梢,遇到了一個(gè)「有趣」的問(wèn)題。假設(shè)有一頁(yè)面布局如下:

下方 50px 懸浮于底部富俄,采用 fixed 布局禁炒,示例如下:

<div class="container">
  <!-- height: 100vh - 50px -->
  <div class="page"></div>
  <!-- fixed bottom, height: 50px -->
  <div class="tabbar">TabBar</div>
</div>
<script>
  window.onload = function () {
    const arr = new Array(100).fill(0).map((_, index) => index + 1)
    const pageEl = document.querySelector('.page')
    const listEl = document.createElement('div')

    arr.forEach(item => {
      const itemElement = document.createElement('div')
      itemElement.innerText = item
      itemElement.className = 'list'
      listEl.appendChild(itemElement)
    })

    pageEl.appendChild(listEl)
  }
</script>

完整示例請(qǐng)看 CodeSandbox齐苛。

測(cè)試下來(lái)看似乎沒(méi)問(wèn)題,可當(dāng)你使用 iPhone 的 Safari 瀏覽器打開此頁(yè)面時(shí)凹蜂,就會(huì)出現(xiàn)如下情況:

截圖中已滑動(dòng)至頁(yè)面最底部,然而 100 被 TabBar 部分擋住了(其他瀏覽器均能正常展示出來(lái))玛痊。

二、原因

我們知道擂煞,vhvw 都是 CSS 中的一種相對(duì)長(zhǎng)度單位蝗拿,1vh 表示 viewport 高度的 1%(vm 同理)。簡(jiǎn)單來(lái)講哀托,viewport 基本上是指當(dāng)前文檔的可見部分,因此 100vh 表示可見文檔的最大高度仓手。

可事實(shí)真是如此嗎?

在 Safari 瀏覽器中嗽冒,100vh 如下圖所示(出自):

按上面所說(shuō),100vh 不應(yīng)該是 viewport 可視區(qū)域的全部高度补履,為什么右圖的高度會(huì)超出的呢添坊?

做個(gè)簡(jiǎn)圖區(qū)分一下吧:

所以,這就是為什么在 Safari 會(huì)被擋住一部分的原因干像。

吐槽一下帅腌,Safari 會(huì)是現(xiàn)代化的 IE 瀏覽器?

三麻汰、尋根問(wèn)底

是 bug 還是故意為之速客?

可以詳細(xì)地看下這篇文章:Viewport height is taller than the visible part of the document in some mobile browsers,然后文章作者給 WebKit 提了個(gè) bug五鲫,其中 Apple 工程師 Benjamin Poulain 的回答如下:

This is completely intentional. It took quite a bit of work on our part to achieve this effect. :)

So, it's a feature, not a bug.

然而溺职,并不是只有 Safari 是這樣做的,比如 iOS 端 Chrome 瀏覽器表現(xiàn)與 iOS 端 Safari 一致... (⊙?⊙)

四位喂、解決方法

盡管這并不是大多數(shù)開發(fā)者想要的浪耘,但很無(wú)奈,我們只能想辦法去「修復(fù)」它塑崖,使得我們的網(wǎng)站在各瀏覽器表現(xiàn)一致七冲。

方案一:使用 -webkit-fill-available

簡(jiǎn)單來(lái)說(shuō),-webkit-fill-available 就是自動(dòng)填滿剩余空間(詳見)规婆。這里使用另一個(gè)示例澜躺,來(lái)說(shuō)明 -webkit-fill-available 的一些問(wèn)題蝉稳,如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <style>
    * {
      padding: 0;
      margin: 0;
      text-align: center;
    }

    body {
      min-height: 100vh;
      display: flex;
      flex-direction: column;
    }
  </style>
  <body>
    <div style="height: 100px; background: blue"></div>
    <div style="flex: 1; background: red"></div>
    <div style="height: 100px; background: green"></div>
  </body>
</html>

以上示例,分別會(huì)有藍(lán)掘鄙、紅耘戚、綠三部分,按預(yù)期結(jié)果操漠,它們應(yīng)該會(huì)占滿整個(gè)可視區(qū)域(完整示例請(qǐng)看 CodeSandbox)收津,而 Safari 中底部綠色部分會(huì)被擋住。然后我們添加在 body 添加上 -webkit-fill-available 看看:

body {
  min-height: 100vh;
  min-height: -webkit-fill-available;
  display: flex;
  flex-direction: column;
}

iOS 上的 Safari 中的表現(xiàn)是正常了浊伙,但是你會(huì)發(fā)現(xiàn) Chrome 下紅色區(qū)域沒(méi)了撞秋,原因是 Chrome 84 起已不再支持 -webkit-fill-available,所以實(shí)際渲染如下:

那么解決方法就是嚣鄙,針對(duì) Safari 瀏覽器才設(shè)置 -webkit-fill-available 即可部服,這里利用到 @support-webkit-touch-callout,如下:

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

@supports (-webkit-touch-callout: none) {
  body {
    min-height: -webkit-fill-available;
  }
}

這樣就 OK 了拗慨,Safari 和 Chrome 表現(xiàn)均如預(yù)期一致。這也是 postcss-100vh-fix 插件的解決方案奉芦。

然而赵抢,以上方案并不適用于這些情況烦却,比如:height: 90vh先巴、height: calc(100vh - 50px)伸蚯,因此才有了方案二剂邮。

方案二:通過(guò) CSS 變量計(jì)算 1vh 所表示的實(shí)際高度

思路:

設(shè)置一個(gè) CSS 變量(比如 --vh)挥萌,然后通過(guò) JavaScript 腳本動(dòng)態(tài)設(shè)置 --vh 的值引瀑,然后使用時(shí)需兼容處理即可(比如,height: 100vh; height: calc(var(--vh) * 100))帜矾。

實(shí)現(xiàn)如下:

<style>
  :root {
    --vh: 1vh;
  }
</style>

<script>
  !(function (n, e) {
    function setViewHeight() {
      var windowVH = e.innerHeight / 100
      n.documentElement.style.setProperty('--vh', windowVH + 'px')
    }
    var i = 'orientationchange' in window ? 'orientationchange' : 'resize'
    n.addEventListener('DOMContentLoaded', setViewHeight)
    e.addEventListener(i, setViewHeight)
  })(document, window)
</script>

使用 vh 時(shí)黍特,需要這樣兼容處理:

.page {
  height: calc(100vh - 50px);
  height: calc(var(--vh) * 100 - 50px);
}

有一個(gè) react-div-100vh 庫(kù)就是獲取 window.innerHeight灭衷,然后將其值設(shè)置為容器高度實(shí)現(xiàn)的翔曲,然而這也是僅可處理 100vh 的情況瞳遍。

至于使用哪一種解決方案,視乎實(shí)際情況而定吧由缆!

五均唉、References

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蚊逢,隨后出現(xiàn)的幾起案子烙荷,更是在濱河造成了極大的恐慌,老刑警劉巖稚叹,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扒袖,死亡現(xiàn)場(chǎng)離奇詭異季率,居然都是意外死亡飒泻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)史辙,“玉大人聊倔,你說(shuō)我怎么就攤上這事〖剩” “怎么了须揣?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵返敬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我秸谢,道長(zhǎng)估蹄,這世上最難降的妖魔是什么沫换? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任垮兑,我火速辦了婚禮漱挎,結(jié)果婚禮上磕谅,老公的妹妹穿的比我還像新娘雾棺。我一直安慰自己捌浩,他們只是感情好尸饺,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布侵佃。 她就那樣靜靜地躺著馋辈,像睡著了一般迈螟。 火紅的嫁衣襯著肌膚如雪尔崔。 梳的紋絲不亂的頭發(fā)上季春,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天载弄,我揣著相機(jī)與錄音宇攻,去河邊找鬼。 笑死嘉涌,一個(gè)胖子當(dāng)著我的面吹牛仑最,可吹牛的內(nèi)容都是我干的词身。 我是一名探鬼主播番枚,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拗馒!你這毒婦竟也來(lái)了诱桂?” 一聲冷哼從身側(cè)響起呈昔,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肝劲,失蹤者是張志新(化名)和其女友劉穎郭宝,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粘室,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹿榜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年犬缨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刺彩。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗡害,死狀恐怖畦攘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叹螟,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站良价,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蚣常。R本人自食惡果不足惜抵蚊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一泌射、第九天 我趴在偏房一處隱蔽的房頂上張望熔酷。 院中可真熱鬧豺裆,春花似錦、人聲如沸躺酒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)劫灶。三九已至,卻和暖如春供汛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雀久。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工岸啡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赫编,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓悦荒,卻偏偏與公主長(zhǎng)得像搬味,于是被迫代替她去往敵國(guó)和親蟀拷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容