display:none与visibility:hidden不得不说的秘密

 CSS布局中大家可能经常会用到display:none和visibility:hidden,可能很多同学都知道这两个属性是用来隐藏元素的;如果说这两个用来隐藏的属性有什么区别,大家可能会说:display:none 隐藏的元素不占据物理空间,visibility:hidden隐藏的元素占据物理空间。visibility可以被子元素继承,而display:none不能被子元素继承....等。这些是正确的

包括我以前也是这么认为的,而且我还认为display:none的元素在构建DOM树时不会参与构建而visibility:hidden的元素会参与构建生成DOM树。但是最近的一场面试中,突然被面试官告知;display:none的元素在构建DOM树时不会参与构建这种说法是错误的,display:none是会被构建DOM树的。于是我就回来查询了一下相关的文献,发现确实是会被参与构建DOM树的;下面我们用一个示例来验证这个消息。

<link rel="stylesheet" href="css/one.css" />

<body>
        <div id="one"></div>
        <div id="two"></div>
        <script src="Test.js"></script>
    </body>

CSS文件如下:

#one{
    display: none;
    width: 500px;
    height: 100px;
    background-color: red;
}
#two{
    visibility: hidden;
    width: 500px;
    height: 100px;
    background-color: green;
}

其中类名为one的div设置为display:none,类名为two的div设置为visibility:hidden

然后我们运行网页,打开浏览器的调试工具可以发现如下图:两个div都在Element元素中被解析出来了

然后我们再验证一下display被加入到DOM树了,我们通过DOM选择器;选择到这两个元素;并将其打印出来

var one = document.getElementById("one");
var two = document.getElementById("two");
console.log(one);
console.log(two);

到这里我们得出了一个结论:即dipslay:none,visibility:hidden都会被构建DOM树

那么它们本质的区别又在哪里呢,这里我们就要详细了解一下浏览器的渲染机制了(我们这里只谈讨chorme浏览器)

浏览器的渲染过程分为以下几步:

1.解析HTML,构建DOM树

2.解析CSS样式表,构建CSSOM(CSS Object Model)

3.将DOM和CSSOM进行合并生成Render Tree(渲染树)

4.根据Render Tree计算布局

5.依据Render Tree进行渲染

一般浏览器常见的渲染流程基本上就是这样,可能有些浏览器产生Render Tree树的规则不一样;这样就造成了不同浏览器之间

存在差异和兼容性的问题。

而根据上面的流程结合我们上面的验证来看:1.display:none的元素会被构建为DOM树,因为解析HTML构建DOM树在前面;而display:none样式的加载在后面一步

2.dispaly:none的元素不会被加入到Render Tree 而visibility:hidden的元素会被加入到Render Tree;

而这也正是为什么visibility会占据空间而display:none不占据空间的原因,没有加入到Render树,那么在计算布局的时候就不会计算display:none元素。但是会计算visibility:hidden的元素。

 

讲到这,大家也应该明白了两者之间的秘密。

另外再提到我写这篇文章时了解的两个概念:重绘(repaint)和回流(reflow)

1.重绘:当Render Tree中的一些元素需要更新属性,但这些属性只会影响元素的外观,风格,而不会影响布局

2.回流:当Render Tree中的一部分(或所有)因为其中元素的规模尺寸、布局、隐藏等改变而需要重新构建Render Tree

时;

从一般的角度而言,就是会页面元素的布局产生影响的会引起回流。而只对外观和风格产生影响的则只会引起重绘。

回流一定会引起重绘,重绘不一定会引起回流;每个页面至少需要一次回流:即页面第一次加载的时候;这时候一定会产生回流因为需要构建Render Tree。

而回流和重绘都是比较消耗浏览器性能的一件事情

关于回流和重绘详细的介绍以及浏览器的渲染机制可以参考这篇文章:http://www.javashuo.com/article/p-rlisrias-cy.html

关于display:none,visibility:hidden,opacity:0之间的一些表现上的区别可以参考这篇文章:https://blog.csdn.net/github_39673115/article/details/77926351

以上文章属于自己个人的理解,如有不正确的地方;请留言指正。谢谢!!!