实战CSS元素可见性

985 阅读4分钟

背景

最近看到jQuery中获取隐藏元素的计算样式时,使用了visibility属性。 由于之前没有完全理解几种不同方法设置元素不可见性之间的区别,感觉平时的业务代码中也不会用到这些-_-(码农),这次碰到了,要好好研究一下。

浏览器构建渲染树

浏览器渲染页面前需要先构建DOM和CSSOM树,在不考虑JavaScript脚本的情况下,这两者分别由HTML和CSS来提供。 CSSOM树和DOM树合并成渲染树,然后用于计算每个可见元素的布局,并输出给绘制流程,将像素渲染到屏幕上。 所以,直接看到的实体就是渲染树,而所谓的元素的不可见指的是在渲染树上看不到该元素。

三种方法设置元素不可见

最初显示样式

原始样式

html代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" >
    <title>元素可见性测试</title>
    <style>
        .parent {
            border: solid 1px #000000;
            padding: 5px;
            position: absolute;
            top: 100px;
            left: 100px;
        }

        .head {
            border: solid 1px #0000FF; 
            width: 100px;
        }

        .bottom {
            border: solid 1px #00FF00; 
            width: 100px;
        }

        .middle {
            height: 100px; 
            width: 100px; 
            background: #FF0000;
            margin-top: 10px;
            margin-bottom: 10px;
        }
    </style>
</head>
<body>
    <div class="parent">
        <div class="head">隐藏元素上部</div>
        <button id="middle" class="middle"></button>
        <div class="bottom">隐藏元素底部</div>
    </div>
</body>
</html>

display:none

display属性主要是用来改变元素的的显示方式,也就是通过改变元素显示角色来改变页面布局。

浏览器渲染结果

display:none样式

可见渲染树中已经隐藏了中间的红色元素,而且渲染树中已经没有了该元素的空间布局存在了,同时该元素无法响应点击事件。

html代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" >
    <title>元素可见性测试</title>
    <style>
        .parent {
            border: solid 1px #000000;
            padding: 5px;
            position: absolute;
            top: 100px;
            left: 100px;
        }

        .head {
            border: solid 1px #0000FF; 
            width: 100px;
        }

        .bottom {
            border: solid 1px #00FF00; 
            width: 100px;
        }

        .middle {
            height: 100px; 
            width: 100px; 
            background: #FF0000;
            margin-top: 10px;
            margin-bottom: 10px;
            display: none;
        }
    </style>
</head>
<body>
    <div class="parent">
        <div class="head">隐藏元素上部</div>
        <button id="middle" class="middle" onclick="alert('click me!')"></button>
        <div class="bottom">隐藏元素底部</div>
    </div>
</body>
</html>

visibility:hidden

visibility属性可以控制整个元素的可见性。当元素处于不可见状态时,元素还是会影响文档的布局,占用和正常显示时相同大小的空间。

浏览器渲染结果

visibility:hidden样式

可见渲染树中没有显示红色部分,但是渲染树中仍然存在该元素所占用的空间。可是点击所在区域,该元素仍然无法响应点击事件。

html代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" >
    <title>元素可见性测试</title>
    <style>
        .parent {
            border: solid 1px #000000;
            padding: 5px;
            position: absolute;
            top: 100px;
            left: 100px;
        }

        .head {
            border: solid 1px #0000FF; 
            width: 100px;
        }

        .bottom {
            border: solid 1px #00FF00; 
            width: 100px;
        }

        .middle {
            height: 100px; 
            width: 100px; 
            background: #FF0000;
            margin-top: 10px;
            margin-bottom: 10px;
            visibility: hidden;
        }
    </style>
</head>
<body>
    <div class="parent">
        <div class="head">隐藏元素上部</div>
        <button id="middle" class="middle" onclick="alert('click me!')"></button>
        <div class="bottom">隐藏元素底部</div>
    </div>
</body>
</html>

opacity:0

opacity属性是设置元素的透明度,当透明度为0,也就表示该元素不可见。所以,该属性不会影响到元素的空间布局。 空间布局和visibility:hidden相同,但是点击所属区域,会响应点击事件。

总结

  • display:none 将元素从渲染树中移除,令元素不可见,同时不响应DOM事件。当要显示该元素时,需要重新设置该属性,浏览器重现显示该元素涉及到重排和重绘操作,比较耗费性能
  • visibiliy:hidden 渲染树中保留了该元素的空间位置,但是元素不可见,同时不响应DOM事件。当要显示该元素时,由于元素布局没有改变,因此只涉及到重绘操作,耗费性能小于display:none
  • opacity:0 渲染树中保留了该元素的空间位置,虽然元素不可见(透明了),但是会响应DOM事件。当要显示该元素时,性能代价比较类似与visibility:hidden