今天在解決 ios 移動端滾動穿透的問題時遇到一個問題,就是判斷元素可否滾動,把這個過程記錄下來。如下以縱向滾動爲例,橫向滾動同理。
嫌麻煩的能夠直接查看代碼。javascript
Element.scrollHeightjava
scrollHeight 是一個元素內容高度的度量,包括因爲溢出致使的視圖中不可見的內容,scrollHeight 的值等於元素在不能出現滾動條的時候展現出視圖中全部內容所須要的最小高度。
若是元素內容能在不出現滾動條的狀況下所有展現,那麼元素的 scrollHeight 和 clientHeight 相等。 MDN
Element.clientHeightios
clientHeight 是指元素內部高度,包括 padding,但不包括 margin、border 以及 橫向滾動條。
clientHeight = CSS height + CSS padding - height of horizontal scrollbar (if present) MDN
根據上面兩個定義,很容易就想到能夠經過比較 scrollHeight 和 clientHeight 的大小來判斷元素是否能夠滾動。最開始我就是這麼作的。git
function eleCanScroll(ele) { return ele.scrollHeight > ele.clientHeight; }
使用以後發現這個方法大部分時候判斷是對的,可是在一些狀況下就出現的誤差。
誤差1
查看demo
子元素超出父元素,並且父元素不設置 overflow: auto
誤差2
查看demo
子元素相對父元素絕對定位github
上面的兩個 demo 中,雖然 box 元素的 scrollHeight 大於 clientHeight,可是並不能滾動。code
其實緣由從 scrollHeight 的定義中就能找到,scrollHeight 是一個元素內容高度的度量,包括因爲溢出致使的視圖中不可見的內容,也就是說,只要元素的子元素沒有徹底在父級內容框中顯示出來,無論是由於定位仍是 translate 偏移致使,父級元素的 scrollHeight 就必定大於 clientHeight。而這裏面不少狀況下父級元素都是不能滾動的。ip
因此經過比較 scrollHeight 和 clientHeight 的大小來判斷元素是否能夠滾動的方法是錯誤的,我看網上有的解決辦法是判斷父級元素的 overflow 屬性,但咱們知道這樣也是不對的。文檔
正確的解決辦法就要從 scrollTop 上入手了。
Element.scrollTopget
一個元素的 scrollTop 值是這個元素的頂部到視口可見內容(的頂部)的距離的度量。當一個元素的內容沒有產生垂直方向的滾動條,那麼它的 scrollTop 值爲0。 MDNscrollTop 能夠被設置爲任何整數值,同時注意:若是一個元素不能被滾動(例如,它沒有溢出,或者這個元素有一個"non-scrollable"屬性), scrollTop將被設置爲0。it
根據上面 scrollTop 的語法咱們就能找到解決方案。咱們能夠設置元素的 scrollTop = 1,再獲取下 scrollTop,若是值變爲 0,說明該元素不能夠滾動。
代碼地址
function eleCanScroll(ele) { if (!ele instanceof HTMLElement) { console.log("fuck off"); return; } if (ele.scrollTop > 0) { return true; } else { ele.scrollTop++; // 元素不能滾動的話,scrollTop 設置不會生效,還會置爲 0 const top = ele.scrollTop; // 重置滾動位置 top && (ele.scrollTop = 0); return top > 0; } }
https://developer.mozilla.org...
https://developer.mozilla.org...
https://developer.mozilla.org...