opacity 用来设置透明度
display 定义创建布局时元素生成的显示框类型
visibility 用来设置元素是否可见。
opacity、visibility、display 这三个属性分别取值 0、hidden、none 都能使元素在页面上看不见,可是他们在方方面面都仍是有区别的。css
举个例子html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .yellow{ width:100px; height:100px; background:yellow; } .red{ width:100px; height:100px; background:red; } </style> </head> <body> <div class="yellow"></div> <div class="red"></div> </body> </html>
最开始的样子 前端
黄色块div元素 使用 opacity:0;
时 segmentfault
黄色块div元素 使用 visibility:hidden;
时 浏览器
黄色块div元素 使用 display:none;
时 app
能够看出,使用 opacity 和 visibility 属性时,元素仍是会占据页面空间的,而使用 display 属性时,元素不占据页面空间。布局
若是子元素什么都不设置的话,都会受父元素的影响,和父元素的显示效果同样,咱们就来举例看看,若是子元素设置的值 和 父元素设置的值不一样会有什么效果。
例子 (opacity属性)spa
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .yellow{ width:100px; height:100px; background:yellow; opacity:0; /* 父元素的 opacity属性取值为0 */ } .blue{ width:50px; height:50px; background:blue; opacity:1; /* 子元素的 opacity属性取值为1 */ } </style> </head> <body> <div class="yellow"> <div class='blue'></div> </div> </body> </html>
例子 (visibility属性)ssr
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .yellow{ width:100px; height:100px; background:yellow; visibility:hidden; /* 父元素的 visibility属性取值为hidden */ } .blue{ width:50px; height:50px; background:blue; visibility:visible; /* 子元素的 visibility属性取值为visible */ } </style> </head> <body> <div class="yellow"> <div class='blue'></div> </div> </body> </html>
例子 (display属性)3d
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .yellow{ width:100px; height:100px; background:yellow; display:none; /* 父元素的 display属性取值为none */ } .blue{ width:50px; height:50px; background:blue; display:block; /* 子元素的 display属性取值为block */ } </style> </head> <body> <div class="yellow"> <div class='blue'></div> </div> </body> </html>
能够看出,使用 opacity 和 display 属性时,父元素对子元素的影响很明显,子元素设置的 opacity 和 display 属性是不起做用的,显示的效果和父元素同样,而使用 visibility 属性时,子元素若是设置为 visibility:visible;
并无受父元素的影响,能够继续显示出来。
这里说的触发事件,是指用户人为的触发的事件,不包括使用 JavaScript 模拟触发的事件。
例子 (opacity属性)
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .yellow{ width:100px; height:100px; background:yellow; opacity:0; } </style> </head> <body> <div class="yellow" onmouseenter="alert(0)"></div> </body> </html>
例子 (visibility属性)
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .yellow{ width:100px; height:100px; background:yellow; visibility:hidden; } </style> </head> <body> <div class="yellow" onmouseenter="alert(0)"></div> </body> </html>
使用 display:none;
就不用举例子了,由于使用 display 属性的话,元素不只看不见,并且也不占据页面空间,全部不会触发事件。
总的来讲,使用 visibility 和 display 属性,自身的事件不会触发,而使用 opacity 属性,自身绑定的事件仍是会触发的。
例子(opacity属性)
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .red{ width:400px; height:40px; background:red; position:relative; } .yellow{ position:absolute; top:0; left:0; width:200px; height:300px; background:yellow; opacity:0; } .blue{ width:200px; height:200px; background:blue; } .red:hover .yellow{ opacity:1; } </style> </head> <body> <div class='red'> <div class='yellow'></div> </div> <p class='blue' onmouseenter=alert(0)></p> </body> </html>
黄色块div元素设置 opacity:0;
,经过定位,遮挡住了 蓝色的p元素,当鼠标移到蓝色p元素上时,并无触发蓝色p元素的事件。
例子(visibility属性)
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .red{ width:400px; height:40px; background:red; position:relative; } .yellow{ position:absolute; top:0; left:0; width:200px; height:300px; background:yellow; visibility:hidden; } .blue{ width:200px; height:200px; background:blue; } .red:hover .yellow{ visibility:visible; } </style> </head> <body> <div class='red'> <div class='yellow'></div> </div> <p class='blue' onmouseenter=alert(0)></p> </body> </html>
黄色块div元素设置 visibility:hidden;
,经过定位,虽然遮挡住了 蓝色的p元素,可是当鼠标移到蓝色p元素上时,仍是触发了蓝色p元素绑定的事件。
和上边同样,display 属性就不举例子了,由于他不会占据页面空间,也就不会遮挡其余元素,就不会影响其余元素触发事件了。
因此,visibility 和 display 属性是不会影响其余元素触发事件的,而 opacity 属性 若是遮挡住其余元素,其余的元素就不会触发事件了。
回流
当页面中的一部分(或所有)由于元素的规模尺寸,布局,隐藏等改变而须要从新构建。这就称为回流(也有人会把回流叫作是重布局或者重排)。
每一个页面至少须要一次回流,就是在页面第一次加载的时候。
dispaly 属性会产生回流,而 opacity 和 visibility 属性不会产生回流。
重绘
当页面中的一些元素须要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的时候,好比background-color。则称为重绘。
dispaly 和 visibility 属性会产生重绘,而 opacity 属性不必定会产生重绘。
元素提高为合成层后,transform 和 opacity 不会触发 repaint,若是不是合成层,则其依然会触发 repaint。
在 Blink 和 WebKit 内核的浏览器中,对于应用了 transition 或者 animation 的 opacity 元素,浏览器会将渲染层提高为合成层。
也可使用 translateZ(0) 或者 translate3d(0,0,0) 来人为地强制性地建立一个合成层。
举个例子
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <div id="target">重绘 repaint</div> <script> var flag = false; setInterval(function () { flag = !flag; target.style.opacity = flag ? 0 : 1; },1000) </script> </body> </html>
咱们能够用 Chrome DevTools 的 Rendering 来看看,
先打开 Rendering
把第一个选项勾选,这个选项会 高亮显示须要重绘的区域。
看看效果
改改代码,增长上个 transition
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> div{ transition:1s; } </style> </head> <body> <div id="target">重绘 repaint</div> <script> var flag = false; setInterval(function () { flag = !flag; target.style.opacity = flag ? 0 : 1; },1000) </script> </body> </html>
再看看效果
加上 transition 后就没有 高亮显示了,这时候 opacity 不会触发重绘。
实际上透明度改变后,GPU 在绘画时只是简单的下降以前已经画好的纹理的 alpha 值来达到效果,并不须要总体的重绘。不过这个前提是这个被修改的 opacity 自己必须是一个图层,若是图层下还有其余节点,GPU 也会将他们透明化。
注意:回流必将引发重绘,而重绘不必定会引发回流。
opacity 是支持 transition的,通常淡入淡出的效果就是这样实现的。
visibility 也是支持 transition 的。
visibility: 离散步骤,在0到1数字范围以内,0表示“隐藏”,1表示彻底“显示”
visibility : hidden;
能够当作 visibility : 0;
visibility : visible;
能够当作 visibility : 1;
只要 visibility 的值大于0就是显示的,因此
visibility:visible 过渡到 visibility:hidden,看上去不是平滑的过渡,而是进行了一个延时。
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .blue{ width:200px; height:200px; background:blue; transition:1s; visibility:visible; } .blue:hover{ visibility:hidden; } </style> </head> <body> <div class='blue'></div> </body> </html>
而若是 visibility:hidden 过渡到 visibility:visible ,则是当即显示,没有延时。
注意
上面这个例子只能是从 visibility:visible 过渡到 visibility:hidden
,不能从 visibility:hidden 过渡到 visibility:visible
。
当元素是 visibility:hidden;
时,自身的事件不会触发,因此像上面这个例子中,直接在蓝色块div元素 上加 hover 事件,要去将自身的 visibility:hidden 过渡到 visibility:visible
是不会起做用的。
可是在其余元素上加事件,来将该元素的 visibility:hidden 过渡到 visibility:visible
是能够的,看例子。
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .red{ width:200px; height:200px; background:red; } .blue{ width:200px; height:200px; background:blue; transition:1s; visibility:hidden; } .red:hover+.blue{ visibility:visible; } </style> </head> <body> <div class='red'></div> <div class='blue'></div> </body> </html>
display 不只不支持transition,它还会使 transition 失效。举个例子看看
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .blue{ width:200px; height:200px; background:blue; } .yellow{ width:100px; height:100px; background:yellow; opacity:0; display:none; transition:1s } .blue:hover .yellow{ opacity:1; display:block; } </style> </head> <body> <div class='blue'> <div class='yellow'></div> </div> </body> </html>
能够看出用了display,支持 transition 的 opacity 属性也没起做用。
这是由于display:none;
的元素,是不会渲染在页面上的,而 transition 要起做用,元素必须是已经渲染在页面上的元素,咱们能够再来看个例子
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .blue{ width:200px; height:200px; background:blue; } .yellow{ width:100px; height:100px; background:yellow; opacity:0; transition:1s } </style> </head> <body> <span>渲染到页面</span> <div class='blue'></div> <script> var span = document.querySelector('span'); span.addEventListener('click',function(){ var yellowDiv = document.createElement('div'); yellowDiv.classList.add('yellow'); var blue = document.querySelector('.blue'); blue.appendChild(yellowDiv); yellowDiv.style.opacity = '1'; }) </script> </body> </html>
给 span 元素绑定事件,点击它的时候,才会把黄色块div元素,渲染到DOM树上,而后改变黄色块div元素的 opacity 属性,opacity 是支持 transition 的,而在这段代码中,并无起做用。
更详细的关于 transition 是否成功 的解读看这里
渲染树决定 transtion 可否成功
要想解决这个问题,咱们能够这样作。
一、把 display 属性换成 visibility 属性
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .blue{ width:200px; height:200px; background:blue; } .yellow{ width:100px; height:100px; background:yellow; opacity:0; visibility:hidden; transition:1s } .blue:hover .yellow{ opacity:1; visibility:visible; } </style> </head> <body> <div class='blue'> <div class='yellow'></div> </div> </body> </html>
二、若是必需要用 display 属性,咱们能够加上定时器来解决这个问题
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <style> .blue{ width:200px; height:200px; background:blue; } .yellow{ width:100px; height:100px; background:yellow; display:none; opacity:0; transition:1s; } </style> </head> <body> <div class='blue'> <div class='yellow'></div> </div> <script> var blue = document.querySelector('.blue'); blue.addEventListener('mouseenter',function(){ var yellowDiv = document.querySelector('.yellow'); yellowDiv.style.display = 'block'; setTimeout(function(){ yellowDiv.style.opacity = '1'; },0); }) </script> </body> </html>