IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    隐藏元素 display:none 与 visibility:hidden 的区别你真的知道吗?

    夕水发表于 2023-10-30 11:20:14
    love 0
    本文参与了1024 程序员节活动,欢迎正在阅读的你也加入。

    隐藏元素 display:none 与 visibility:hidden 的区别你真的知道吗?

    有关隐藏元素的方式 display: none 与 visibility:hidden 的区别,这可以说是 css 面试题当中最常见的一道题了。相信大多数开发者被问到的第一答案就是:
    display: none 不占据空间,visibility: hidden 占据空间。但实际上两者之间的区别并不只是不占据空间这么简单,且听我娓娓道来。

    区别之一: visibility 拥有继承性

    什么意思呢? 我们知道,如果一个元素的 visibility 设置为 hidden,它的子元素也会被隐藏,那么你知道子元素被隐藏的原理是什么吗?就是继承性。简单来说,就是子元素也继承了 visibility:hidden 的特性。换句话说,如果我们将子元素修改成 visibility: visible,你会发现子元素不再是隐藏,而是显示。来看一个例子感受一下:

    html 代码如下:

    <div class="vh-parent">
      <div class="vh-inherit-child">这是继承子元素的hidden隐藏</div>
      <div class="vv-child">子元素设置了visibility: visible之后又显示了</div>
    </div>

    css 代码如下:

    .vh-parent {
      visibility: hidden;
    }
    .vv-child {
      visibility: visible;
    }

    实际运行效果如下图所示:

    1.png

    区别之二: visibility 不会影响 css 计数器

    visibility:hidden 不会影响计数器的计数,这和 display:none 完全不一样。举个例子,如下 CSS 和 HTML 代码:

    <ol>
      <li>列表</li>
      <li class="dn">列表</li>
      <li>列表</li>
      <li>列表</li>
    </ol>
    <ol>
      <li>列表</li>
      <li class="vh">列表</li>
      <li>列表</li>
      <li>列表</li>
    </ol>
    .vh {
      visibility: hidden;
    }
    .dn {
      display: none;
    }
    ol {
      border: 1px solid;
      margin: 1em 0;
      counter-reset: test;
    }
    li:after {
      counter-increment: test;
      content: counter(test);
    }

    实际运行效果如下图所示:

    2.png

    可以看到,visibility:hidden 虽然让其中一个列表不可见了,但是其计数效果依然存在。相比之下,设置 display:none 的列表就完全没有参与计数运算。

    区别之三: visibility 过渡效果有效,而 display 则无效

    CSS3 transition 支持的 CSS 属性中有 visibility,但是并没有 display。如以下示例:

    /* 过渡效果无效 */
    .test {
      display: none;
      position: absolute;
      opacity: 0;
      transition: opacity 0.25s;
    }
    .test:hover {
      display: block;
      opacity: 1;
    }
    /* 过渡效果无效 */
    .test {
      position: absolute;
      opacity: 0;
      transition: opacity 0.25s;
      visibility: hidden;
    }
    .test {
      visibility: visible;
      opacity: 1;
    }

    由于 transition 可以延时执行,因此,和 visibility 配合可以使用纯 CSS 实现 hover 延时显示效果,由此提升我们的交互体验。来看如下一个示例:

    <table>
      <tr>
        <td>数据1</td>
        <td>数据2</td>
        <td>
          <a href>操作▾</a>
          <div class="list">
            <a href>编辑</a>
            <a href>删除</a>
          </div>
        </td>
      </tr>
      <tr>
        <td>数据1</td>
        <td>数据2</td>
        <td>
          <a href>操作▾</a>
          <div class="list">
            <a href>编辑</a>
            <a href>删除</a>
          </div>
        </td>
      </tr>
    </table>
    td {
      padding: 5px 10px;
      border: 0;
      background: #fff;
      font-size: 14px;
    }
    
    td a {
      display: block;
    }
    
    .list {
      width: 80px;
      position: absolute;
      visibility: hidden;
      border: 1px solid #ccc;
      background: #fff;
    }
    
    td:hover .list {
      visibility: visible;
      transition: visibility 0s 0.2s;
    }
    
    .list a {
      padding: 5px 10px;
      color: #333;
    }
    
    .list a:hover {
      background-color: #f5f5f5;
    }

    效果如下图所示:

    3.png

    以上是一个很常见的 hover 悬浮显示列表效果,而且有多个触发点相邻,对于这种 hover 交互,如果在显示的时候增加一定的延时,可以避免不经意触碰导致覆盖目标元素的问题。如果没有增加延时效果,则会存在如下情况:我本来想去 hover 第二行的“操作”文字,但是由于鼠标光标移动路径不小心经过了第一行的“操作”,结果把第二行本来 hover 的“操作”覆盖了,必须重新移出去,避开干扰元素,重新 hover 才行。如此一来,对用户体验就不好了。而恰好 visibility 就可以处理这个问题。

    区别之四: visibility 可以获得元素的尺寸位置,而 display 则无法获取

    在实际开发中,我们会遇到这样的场景:我们需要对隐藏元素进行尺寸和位置的获取,以便对交互布局进行精准定位。这时候如果使用 display:none 来隐藏元素,我们获取到元素的尺寸位置则是 0,但是 visibility 则不会。js 代码如下:

    console.log('clientWidth: ' + element.clientWidth);
    console.log('clientHeight: ' + element.clientHeight);
    console.log('clientLeft: ' + element.clientLeft);
    console.log('clientTop: ' + element.clientTop);
    console.dir(element.getBoundingClientRect());

    因此面对以上的场景,我们更应该选择 visibility 来隐藏元素。

    区别之五: visibility 在无障碍访问这一块比 display 更友好

    视觉障碍用户对页面的状态变化都是通过声音而非视觉感知的,因此有必要告知其准确信息。

    通过本文,我们了解到了 visibility 与 display 的详细区别,在面试的时候我们也不会只回答的片面了,知晓以上的区别能给我们的面试加分。

    隐藏元素方式

    最后分享一些隐藏元素的方式:

    1. 如果希望元素不可见,同时不占据空间,辅助设备无法访问,同时不渲染,可以使用<script>标签隐藏。例如:
    <script type="text/html">
      <img src="1.jpg" />
    </script>

    <script>标签是不支持嵌套的,因此,如果希望在<script>标签中再放置其他不渲染的模板内容,可以试试使用<textarea>元素。例如:

    <script type="text/html">
      <img src="1.jpg" />
      <textarea style="display:none;">
        <img src="2.jpg">
      </textarea
      >
    </script>
    1. 如果希望元素不可见,同时不占据空间,辅助设备无法访问,但资源有加载,DOM 可 访问,则可以直接使用 display:none 隐藏。例如:
    .hidden {
      display: none;
    }
    1. 如果希望元素不可见,同时不占据空间,辅助设备无法访问,但显隐的时候可以有 transition 淡入淡出效果,则可以使用:
    .hidden {
      position: absolute;
      visibility: hidden;
    }
    1. 如果希望元素不可见,不能点击,辅助设备无法访问,但占据空间保留,则可以使用 visibility:hidden 隐藏。例如:
    .hidden {
      visibility: hidden;
    }
    1. 如果希望元素不可见,不能点击,不占据空间,但键盘可访问,则可以使用 clip 剪裁隐藏。例如:
    .clip {
      position: absolute;
      clip: rect(0 0 0 0);
    }
    .out {
      position: relative;
      left: -999em;
    }
    1. 如果希望元素不可见,不能点击,但占据空间,且键盘可访问,则可以试试 relative 隐藏。例如,如果条件允许,也就是和层叠上下文之间存在设置了背景色的父元素,则也可以使用更友好的 z-index 负值隐藏。例如:
    .lower {
      position: relative;
      z-index: -1;
    }
    1. 如果希望元素不可见,但可以点击,而且不占据空间,则可以使用透明度。例如:
    .opacity {
      position: absolute;
      opacity: 0;
      filter: Alpha(opacity=0);
    }
    1. 如果单纯希望元素看不见,但位置保留,依然可以点可以选,则直接让透明度为 0。例如:
    .opacity {
      opacity: 0;
      filter: Alpha(opacity=0);
    }
    1. 在标签受限的情况下希望隐藏某元素文字,例如:
    .hidden {
      text-indent: -120px;
    }
    1. 如果希望显示的时候可以加一个 transition 动画,可以使用 max-height 进行隐藏。
    .hidden {
      max-height: 0;
      overflow: hidden;
    }
    注: 以上内容阅读《css世界》而整理。


沪ICP备19023445号-2号
友情链接