隐藏/透明元素会影响渲染性能吗?

Che*_*tah 5 html javascript css web-component

所以我正在编写一个聚合物应用程序。我已经为加载覆盖层编写了一个非聚合物 Web 组件,我可以在加载 Polymer 时以及应用程序 Websocket 连接/重新连接时显示该组件。

下面是一些 CSS 的运用,我必须给出我正在做的事情的指示:

  .overlay {
    background: #000;
    bottom: 0;
    height: 100%;
    left: 0;
    opacity: 0;
    pointer-events: none;
    position: fixed;
    right: 0;
    transition: opacity 0.2s;
    top: 0;
    width: 100%;
    z-index: 9999999;
  }

  .overlay[opened] {
    opacity: 0.8;
    pointer-events: auto;
  }

  .loader {
    display: none;
  }

  .overlay[opened] .loader {
    display: block;
  }
Run Code Online (Sandbox Code Playgroud)

现在,这个覆盖层和基于 CSS 的加载器动画仅在实际加载应用程序时使用,但是如果 WebSocket 断开连接,它也会显示。

我的问题是,出于性能原因,我是否应该从 DOM 中完全删除该元素,然后在需要时将其添加回来?覆盖层在不使用时完全透明并且加载器动画被隐藏的事实是否意味着它们对绘图性能没有影响?

注意:如果可能的话,我希望避免“不要微优化”答案;)

And*_*hiu 4

长话短说:

一般来说,当对渲染元素的更改触发 DOM 中后续元素的重绘或resize在其父元素上触发时,渲染元素会影响页面性能,因为resize每秒触发高达 100 次可能会导致昂贵的成本,具体取决于设备。


只要对元素的更改不会触发 DOM 树中后续元素的重绘,将其渲染、隐藏在某些不透明元素后面(或在内容上方,使用 和opacity:0pointer-events:none与根本不显示之间的区别就微不足道。

对元素的更改不会触发除其自身之外的任何内容的重绘,因为它已经触发了position:fixed。如果它有,或者如果通过不会触发后续同级(例如和 )position:absolute重绘的属性对其进行更改,情况也是如此。transformopacity

除非加载程序对渲染引擎的负担非常重(这种情况很少发生 - 想想具有 3D 场景、材质和灯光映射的 WebGL 加载程序 - 在这种情况下,最好在不向用户显示时不显示它),否则差异如此之小,真正的挑战是在性能方面衡量这种差异。

事实上,如果渲染它并且仅更改其属性总体上并不比切换其属性便宜,我不会感到惊讶opacitypointer-events因为display浏览器不必在每次打开它时从 DOM 添加/删除它/离开。但是,真正的问题是:我们如何衡量它?


编辑:实际上,我做了一个小型测试工具,有 10k 模态。我在 Linux 上的 Chrome 中得到了以下结果:

`opacity` average: 110.71340000000076ms | count: 100
`display` average: 155.47145000000017ms | count: 100
Run Code Online (Sandbox Code Playgroud)

...所以我的假设是正确的:display总体来说更贵。

除了少数例外,这些opacity变化大部分都是围绕的,删除节点时变化速度更快,但添加节点时变化速度更慢。110msdisplay

请随意在不同的浏览器、不同的系统上自行测试:

`opacity` average: 110.71340000000076ms | count: 100
`display` average: 155.47145000000017ms | count: 100
Run Code Online (Sandbox Code Playgroud)
$(window).on('load', function () {
  let displayAvg = 0, displayCount = 0,
      opacityAvg = 0, opacityCount = 0;
  for (let i = 0; i < 10000; i++) {
    $('body').append($('<div />', {
      class: 'modal',
      html:'10k &times; modal instances'
    }))
  }
  $(document)
    .on('click', '#display', function () {
      $('.modal').removeClass('opacity');
      let t0 = performance.now();
      $('.modal').toggleClass('display');
      setTimeout(function () {
        let t1 = performance.now();
        displayAvg += (t1 - t0);
        console.log(
          '`display` toggle took ' + 
          (t1 - t0) +
          'ms \n`display` average: ' + 
          (displayAvg / ++displayCount) + 
          'ms | count: ' + 
          displayCount
        );
      })
    })
    .on('click', '#opacity', function () {
      $('.modal').removeClass('display');
      let t0 = performance.now();
      $('.modal').toggleClass('opacity');
      setTimeout(function () {
        let t1 = performance.now();
        opacityAvg += (t1 - t0);
        console.log(
          '`opacity` + `pointer-events` toggle took ' + 
          (t1 - t0) + 
          'ms \n`opacity` average: ' + 
          (opacityAvg / ++opacityCount) + 
          'ms | count: ' + 
          opacityCount
        );
      });
    })
});
Run Code Online (Sandbox Code Playgroud)
body {
  margin: 0;
}
.buttons-wrapper {
  position: relative;
  z-index: 1;
  margin-top: 3rem;
}
.modal {
  height: 100vh;
  width: 100vw;
  position: fixed;
  top: 0;
  left: 0;
  padding: 1rem;
}
.modal.display {
  display: none;
}
.modal.opacity {
  opacity: 0;
  pointer-events: none;
}
.as-console-wrapper {
  z-index: 2;
}
Run Code Online (Sandbox Code Playgroud)

但这个平均值是针对 10k 元素的。将其除以 10k,实际上没有任何区别:我们所说的时间不到一毫秒的 0.45%。