专栏首页FEWY关于opacity、visibility、display属性的一道CSS面试题

关于opacity、visibility、display属性的一道CSS面试题

说明

问题: 一个下拉菜单,结构如下,

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
       div{
         width:400px;
         height:40px;
         background:red;
         position:relative;
       }
       div ul{
        position:absolute;   
        top:0;
        left:0;
        width:200px;
        height:300px;
        background:yellow;
       }
       p{
         width:200px;
         height:200px;
         background:blue;
       }
  </style>
 </head>
 <body>
      <div>
         <ul>
            <li>菜单一</li>
            <li>菜单二</li>
            <li>菜单三</li>
         </ul>
      </div>

      <p onmouseenter=alert(0)></p>
 </body>
</html>

鼠标移入div,显示菜单ul,移出后隐藏菜单ul,只使用CSS,如何实现既有淡入淡出的效果,而又不影响其他元素,不产生回流?

实现

这个问题,看上去似乎很简单,有些同学一定会想到,加透明度就能就解决,来看下是不是。

代码

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
       /* 红色块  div */
       div{
         width:400px;
         height:40px;
         background:red;
         position:relative;
       }
       /*  黄色块 ul */
       div ul{
        position:absolute;    /* 菜单ul绝对定位 */
        top:0;
        left:0;
        width:200px;
        height:300px;
        background:yellow;
        opacity:0;           /* 开始透明度为0 */
        transition:opacity .5s;      /*  0.5s完成 透明度0-1的变化 */
       }
       /* 蓝色块 p */
       p{
         width:200px;
         height:200px;
         background:blue;
       }
       div:hover ul{
         opacity:1;         /* 鼠标进入div,ul的透明度从0过渡到1 */
       }
  </style>
 </head>
 <body>
      <div>
         <ul>
            <li>菜单一</li>
            <li>菜单二</li>
            <li>菜单三</li>
         </ul>
      </div>

      <p onmouseenter=alert(0)></p>
 </body>
</html>

效果图

明显,并没有达到我们需要的效果,当鼠标进入蓝色块的时候,没有触发绑定的事件,而是把菜单显示出来了,这已经是很大的影响了,这主要是因为,opacity属性只是改变透明度,并不是真的让这个元素消失。

说到这,你也许会想到用display属性,但是不可以,首先,display不支持过渡,也就是说,用了他,淡入淡出的效果就没有了,而且他还会产生会回流和重绘,所以这里,我们给他用 visibility 属性就可以了,visibility 属性,支持过渡,而且不会产生回流,虽然 visibility=hidden; 会占据页面空间,但是并不影响其他元素的事件触发和显示。

代码

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <style>
       /* 红色块  div */
       div{
         width:400px;
         height:40px;
         background:red;
         position:relative;
       }
       /*  黄色块 ul */
       div ul{
        position:absolute;    /* 菜单ul绝对定位 */
        top:0;
        left:0;
        width:200px;
        height:300px;
        background:yellow;
        opacity:0;           /* 开始透明度为0 */
        transition:opacity .5s;      /*  0.5s完成 透明度0-1的变化 */

        visibility:hidden;   /* 增加 */
       }
       /* 蓝色块 p */
       p{
         width:200px;
         height:200px;
         background:blue;
       }
       div:hover ul{
        opacity:1;         /* 鼠标进入div,ul的透明度从0过渡到1 */

        visibility:visible;    /* 增加 */
       }
  </style>
 </head>
 <body>
      <div>
         <ul>
            <li>菜单一</li>
            <li>菜单二</li>
            <li>菜单三</li>
         </ul>
      </div>

      <p onmouseenter=alert(0)></p>
 </body>
</html>

效果图

这样我们就实现了,需要的效果。

对比分析

问题解决了,我们来分析一下,opacity、display、visibility这三个属性。 说之前,我们先讲两个概念,回流和重绘。

回流

当页面中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(也有人会把回流叫做是重布局或者重排 )。每个页面至少需要一次回流,就是在页面第一次加载的时候。

重绘

当页面中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的时候,比如background-color。则称为重绘。

注意:回流必将引起重绘,而重绘不一定会引起回流。

从图中应该能很清楚看出,他们之间的区别了,要注意的是: visibility支持过渡 visibility属性虽然支持过渡,但是,不是平滑的过渡,而是进行了一个延时,并且它只是 从 visible 过渡 到 hidden 有延迟,从 hidden 过渡到 visible 不延迟,如图

透明度(opacity)不会触发重绘

实际上透明度改变后,GPU在绘画时只是简单的降低之前已经画好的纹理的alpha值来达到效果,并不需要整体的重绘。不过这个前提是这个被修改 opacity 本身必须是一个图层,如果图层下还有其他节点,GPU也会将他们透明化

总结

最开始的问题,一般是会出现在做一些鼠标悬停特效的时候,鼠标悬停,出现一个div,或者img,而这些元素刚开始是看不见的,他们定位在页面上,如果他们只是透明度发什么变化,很有可能,影响到其他的元素不能触发事件。

简单理解就像,一个a,上面有一个div,div的透明度为0,那么a就无法跳转了,div虽然看不见,但是还是存在的,挡住了a,感觉就像是a上面有一块玻璃,挡住了他。要解决问题,就要给div用上visibility属性。

这篇文章重点还是说最开始提到的那个问题,而对于 opacity、visibility、display 这三个属性并没有进行非常详细的对比分析,所以后来又写了一篇文章。 CSS中用 opacity、visibility、display 属性将 元素隐藏 的 对比分析

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CSS transition delay简介与进阶应用

    我相信这是一个很常见的一个需求,有很多种方式能够实现,但是,其实现方式的原理各不相同,也有利有弊。

    黄Java
  • Web 隐藏技术:几中隐藏 Web 中的元素方法及优缺点

    在 Web 开发中出于多种原因,我们需要隐藏元素。 例如,一个按钮应该在移动中可见,而在桌面视口中隐藏。 或者,在移动设备上隐藏但要在桌面上显示的导航元素。 隐...

    前端小智@大迁世界
  • 总结一些,我在书写 CSS 的时候,经常犯的错误!

    当我们非常专注写代码时候,我们往往会无意识的写出一些无效CSS代码。 我把这种称为 “潜意识错误”。 导致这种错误后,我们经常会反问自己:“为什么我写出这样低级...

    前端小智@大迁世界
  • 用 CSS 隐藏页面元素的 5 种方法

    用 CSS 隐藏页面元素有许多种方法。你可以将 opacity 设为 0、将 visibility 设为 hidden、将 display 设为 none 或者...

    疯狂的技术宅
  • CSS隐藏元素的方法

    使用CSS隐藏元素的主要方式有diaplay: none;、opacity: 0;、visibility: hidden;、position: absolute...

    WindrunnerMax
  • CSS魔法堂:Transition就这么好玩

     以前说起前端动画必须使用JS,而CSS3为我们带来transition和@keyframes,让我们可以以更简单(声明式代替命令式)和更高效的方式实现UI状态...

    ^_^肥仔John
  • CSS魔法堂:Transition就这么好玩

    ^_^肥仔John
  • CSS实现渐隐渐现效果

    实现渐隐渐现效果是比较常见的一种交互方式,通常的做法是控制display属性值在none和其它值之间切换,虽说功能可以实现,但是效果略显生硬,所以会有这样的需求...

    WindrunnerMax
  • 【前端芝士树】IE 静态页兼容指南

    使用 font-awesome 的动画时(loading 效果),倘若用 display 控制显隐,则在 IE 下会表现异常。 图标会瞬间显示出来,但是却没有动...

    CloudCat

扫码关注云+社区

领取腾讯云代金券