判断元素是否有滚动条

8,927 阅读2分钟

判断是否有滚动条的需求在弹窗插件中用得较多,因为弹窗大多会添加overflow: hidden属性,如果页面超过一屏的话,添加这个属性之后页面会有晃动。

为了增强用户体验,通过判断是否有滚动条而添加margin-left属性以抵消overflow: hidden之后的滚动条位置。

// 判断竖向滚动条
element.scrollHeight > element.clientHeight;
// 判断横向滚动条
element.scrollWidth > element.clientWidth;

特殊情况

    当元素指定了overflow: hidden是,是不会出现滚动条的,所以需要对元素是否应用了overflow: hidden进行判断。

// 封装函数
function hasScrolled(ele, dir = "vertical"){
  // 判断的方向是否设置了overflow: hidden
  let style = window.getComputedStyle(ele);
  if( (dir == "vertical" && style.overflowY == "hidden") 
     ||
      (dir == "horizontal" && style.overflowX == "hidden")
  )return false;
  
  // 在判断完overflow不为hidden后,再通过两个属性来判断。
  if(dir == "vertical"){
    return (ele.scrollHeight > ele.clientHeight);
  }else{
    return (ele.scrollWidth > ele.clientWidth);
  };
};

    但是,以上的方法不严谨,当容器产生外边距合并的时候,也是ele.scrollWidth > ele.clientWidth。

<div class="box">
  <h1>子元素内部内容</h1>
</div>

<script>
    let box = document.querySelector(".box");

    console.log("scrollHeight: " + box.scrollHeight) // scrollHeight: 63
    console.log("clientHeight: " + box.clientHeight) // clientHeight: 42
    console.log("是否有滚动条:", box.scrollHeight > box.clientHeight) // 是否有滚动条: true
</script>
// 做好的做法应该是:
function hasScrolled(ele, dir = "vertical"){
  let eleScroll = dir == "vertical" ? "scrollTop" : "scrollLeft";
  
  let result = !!ele[eleScroll]; // 判断scroll数值是否为0,还是其他值
  // 如果是其他数值(非0)这表示有滚动条
  // 如果是0,则尝试移动一下滚动条,判断是否能够移动
  if(!result){
    ele[eleScroll] = 1; // 尝试移动滚动条
    result = !!ele[eleScroll]; // 再次确认数值
    ele[eleScroll] = 0; // 恢复原位
  };
  
  return result; // 得出结果
};

计算滚动条宽度的方法

因为移动端浏览器的滚动条都是不占据页面宽度的透明样式,所以为了进一步增强用户体验,我们还需要计算滚动条的宽度,根据情况添加合理的margin-left

// 计算滚动条宽度的方法:新建一个带有滚动条的DIV元素,再计算该元素offsetWidth和clientWidth的差值。
function getScrollbarWidth() {

    var scrollDiv = document.createElement("div");
    scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
    document.body.appendChild(scrollDiv);
    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
    document.body.removeChild(scrollDiv);

    return scrollbarWidth;
};