美文网首页
overflow属性引发的浏览器滚动条血案

overflow属性引发的浏览器滚动条血案

作者: 简森w | 来源:发表于2018-05-04 12:43 被阅读0次

    案发现场

    今天给后台的表格组件替换为一个前同事写的表格组件,替换完发现除了滚动条不能用鼠标滚动以外,其他都没什么大问题。我是一个跟任何东西都可以较劲的人,我不信一个小小的滚动条还能奈我何?于是就发生了这个血案。从看源码,到问前同事,足足浪费了我一个下午来找问题,深深地感到自己的能力是如此的不足。

    案发详情

    滚动条归属的问题。

    我们都知道,如何页面超过了浏览器窗口的大小,浏览器会自动生成一个滚动条。这个滚动条是属于谁的?是属于html元素还是body元素的?

    都不是!!

    当一个子元素超过了其父元素的限定高度并且在父元素设置了overflow:auto或者overflow:scroll父元素容器就会产生一个滚动条,这个滚动条毫无疑问是归属于父元素的。直接看demo01,以下是demo01的主要代码:

    <div class="parent">
        parent
        <div class="child">
            child
        </div>
    </div>
    
    body{
        margin:0;
    }
    .parent{
        height:400px;
        border:1px solid #ddd;
        overflow:auto;
    }
    
    .child{
        height:800px;
        background-color:#eee;
    }
    

    可以看到,child撑开了parent的高度,于是parent生成了滚动条,滚动条属于parent,这个是没有争议的。

    如何判断滚动条的归属呢?

    一种直观的方法:可以通过控制台的Element面板,把鼠标hover在parent元素上,可以看到滚动条是在元素内部的。(在Mac下,滚动条的表现形式不太一样,只有滚动的时候才会出现滚动条,没有滚动时自动隐藏)

    另一种方法是可以通过对元素添加scroll监听事件来判断。

    如果是body下的直接子元素的高度超过了body的限定高度,并且给body增加overflow :auto,这时生成的滚动条是属于谁的?看一下例子demo02,以下是主要代码:

    <div class="child">
        Child
    </div>
    
    html, body{
        height:100%;
    }
    body{
        margin:0;
        overflow:auto;
    }
    .child{
        height:1000px;
        background-color:#eee;
    }
    

    咦,好像滚动条并不属于body元素??确实不属于body,也不属于html。Mac下按照上面第一种方法观察,滚动条好像是属于html元素的,但其实不然,可以通过给元素添加scroll事件的监听就可以发现,滚动的时候并不会触发html元素或者body元素的scroll事件。

    //监听window窗口的滚动事件
    window.addEventListener('scroll', (e) => {
        console.log('window');
    })
    //监听document对象的滚动事件
    document.addEventListener('scroll', (e) => {
        console.log('document');
    })
    //监听html元素的滚动事件
    document.documentElement.addEventListener('scroll', (e) => {
        console.log('html');
    })
    //监听body元素的滚动事件
    document.body.addEventListener('scroll', (e) => {
        console.log('body');
    })
    

    上面的四个监听器,滚动的时候只有前两个才会被触发,所以证明滚动条是属于document对象的。

    为什么window也能监听到scroll事件呢?这是因为事件冒泡

    当html元素也添加overflow:auto时,滚动条会是谁的呢?看例子demo03

    这时,滚动条貌似是属于body的?是的没错,就是属于body的,用监听器来监听一下滚动事件,只会触发document.body的监听器,而不会触发windowdocument的。

    为什么会这样?应该不仅只有我一个人才发现滚动条这个坑的吧?TAT

    先来回顾一下overflow有哪些值:

    /* 默认值。内容不会被修剪,会呈现在元素框之外*/
    overflow: visible;
    
    /* 内容会被修剪,并且其余内容不可见 */
    overflow: hidden;
    
    /* 内容会被修剪,浏览器会显示滚动条以便查看其余内容 */
    overflow: scroll;
    
    /* 由浏览器定夺,如果内容被修剪,就会显示滚动条 */
    overflow: auto;
    
    /* 规定从父元素继承overflow属性的值 */
    overflow: inherit;
    
    

    于是得出结论(也可以说个人猜测,因为不一定正确):

    htmlbody仅有一个元素会产生滚动条时,这个滚动条会默认归属于document

    htmlbody元素的overflow属性都是默认值auto时,因为body高度可能超过html的高度,这时就会产生一个滚动条,这个滚动条属于document的,所以如果body再产生一个滚动条,就只能是属于body自己的了。

    鼠标滚轮事件

    页面出现滚动条时,我们可以用鼠标滚轮来对页面进行纵向滚动,那是否可以组织这个滚动行为呢?

    肯定是可以的。e.preventDefault()就是阻止事件的默认行为,在mousewheel事件监听里加上这句,就能阻止鼠标滚轮触发滚动事件了。

    戳栗子demo04

    因为这个,让我在组件源码里折腾了好一会,当然不是不知道e.preventDefault(),是忽略了它的作用。


    因为工作忙,这篇文章前后写了好久,当时的一些思路灵感都已经消逝了,写不下去了,先到这为止吧,之后有想起什么遗漏的再补上。

    相关文章

      网友评论

          本文标题:overflow属性引发的浏览器滚动条血案

          本文链接:https://www.haomeiwen.com/subject/vqddrftx.html