iOS 上,fixed 元素內的輸入元素,獲取焦點時的游標錯位問題
阿新 • • 發佈:2019-02-11
RT,如果一個輸入元素(input, textarea …)的父容器設定了 position: fixed
,當這個元素獲取焦點時,會觸發底部鍵盤的彈起。這時在輸入框內打字的時候,會發現其游標錯位了,一般會跑到下方。
當你專注於一個輸入時,瀏覽器會自動向下滾動,以便將焦點輸入突出顯示給使用者,這就造成了頁面內高度浮動,導致游標位移。
遺憾的是,截至目前,iOS 11.x 上也有這個問題。
曾經嘗試過的方案
當元素獲取焦點時,改變父容器的定位方式:fixed
> absolute
for (let evt of ['focus', 'blur']) { const isFocus = evt === 'focus' const fn = isFocus ? 'add' : 'remove' inputDOMNode.addEventListener(evt, () => { parentDOMNode.classList[fn]('input-focus') htmlDOMNode.classList[fn]('no-scroll') bodyDOMNode.classList[fn]('no-scroll') isFocus && setScrollTop(0) }) }
.input-focus {
position: absolute;
...
}
.no-scroll {
height: 100%;
overflow: hidden;
}
監聽了輸入元素 focus
和 blur
事件,為父元素新增或移除某些樣式。
當
position: absolute
時,輸入框的定位方式需要手動設定(這裡採取了頂部對齊);.no-scroll
是為了禁止body
的滾動,保證輸入框可見。
但是這個方案在部分 Android 裝置上,當鍵盤收起時並不會觸發輸入元素的 blur
事件,往往還需要使用者主動點選頁面的其他區域,算是一點小遺憾吧。
終極解決方案(推薦)
直接給 html
, body
元素設定樣式
html,
body {
-webkit-overflow-scroll: touch !important;
overflow: auto !important;
height: 100% !important;
}
-webkit-overflow-scrolling: touch; /* 當手指從觸控式螢幕上移開,會保持一段時間的滾動 */
overflow: auto; /* 由瀏覽器定奪,如果內容被修剪,就會顯示滾動條 */
當輸入元素獲取焦點時,鍵盤彈起,輸入元素被頂到了鍵盤的上方,此時使用者的手指會從觸控式螢幕上移開,輸入元素會保持一段時間的滾動,從而游標的位置可以被正確計算。
!important
在這裡是為了防止這些屬性會因為瀏覽器優先順序過高而發生變化。
有點小遺憾的是,!important
侵入性有些高。