移動端鍵盤遮擋頁面原理分析

wxlworkhard發表於2018-01-26

在移動端 focus 輸出框時會調起軟鍵盤,這時視口(viewport)的高度變小,一螢幕展示的內容變少,我們可以滾動更長的距離。
JS 如何捕獲視口高度的變化,答案是 window.innerHeight,具體如下:

enter image description here

正常情況是 focus 輸入框,鍵盤彈出,輸入框在視口垂直居中,頁面無遮擋(通過滾動頁面可以看到完整的頁面內容)。
但現實是存在各種問題,但可以歸結為兩類:頁面遮擋問題和滾動條位置問題。
這裡列舉幾個場景,最後給出解決方案(可根據自己的實際情況再進行擴充套件)。

頁面遮擋問題

某些安卓手機 window.innerHeight 不會因為彈出鍵盤而變化,無法捕獲視口高度變化,頁面內容被遮擋,可以通過增加內容的高度強制展示全部內容,程式碼如下:

const contentHeight = document.body.clientHeight;
document.body.style.height = `${contentHeight + 250}px`;
// window.scrollTo(0, ......) //手動滾動到相應位置

Tips:iOS8、iOS9 的 window.innerHeight 也不變化,但和安卓的表現不一樣,具體如下:

  • iOS8 頁面表現完全正常,無需做任何相容性處理
  • iOS9 頁面無遮擋,但滾動條的位置錯誤,可以在彈出鍵盤後(setTimeout 300)手動呼叫 window.scrollTo

滾動條位置問題

安卓系統的 Vivo 手機可以捕獲視口高度變化,但是滾動條位置有問題,需要手動呼叫 window.scrollTo
Tips:iOS10 及以上正常但是呼叫 window.scrollTo 就會出問題。

解決方案程式碼

enter image description here

在 focus 輸入框時呼叫 compatMobileKeyboard('focus'),blur 時 compatMobileKeyboard('blur')

程式碼比較簡單,主要思路是在彈出/隱藏鍵盤前後比較 window.innerHeight 的變化,如果變化明顯,即大於 200 則認為能捕獲到視口變化。

為什麼不比較是否相等,是因為 iOS 瀏覽器的頁面最大化(就是滾動時瀏覽器的位址列會變小,底部的 banner 條會隱藏,在安卓的 UC 瀏覽器也有該功能)時 window.innerHeight 會有大概 69 的變化,這裡指定 200 是為了和最大化功能區別開。

根據能否捕獲視口變化分成無遮擋和有遮擋兩類,然後再處理滾動條位置的問題。

模擬滾動 iScroll

這裡沒有使用模擬滾動,模擬滾動會以視口的高度為基準,滾動超出視口的內容部分,上面列出的一些場景是無法捕獲視口變化的,所以模擬滾動肯定會存在問題。

可以使用 scrollIntoView 來解決問題,但還有一些細節要處理,例如:彈出鍵盤並 scrollIntoView 到輸出框時,這時滾動會有問題,可以在這個時機禁用滾動。

個人建議這種場景不要使用模擬滾動。

相關文章