使用过渡时的问题+不透明度变化+溢出隐藏

时间:2015-07-29 06:52:21

标签: javascript html css css3 css-animations

如果您看到我共享的代码示例,您可以看到框外的覆盖图。我将问题追溯到transition属性。

我想删除div之外的内容。溢出并不像它应该的那样工作。 (删除transition有效,但我希望尽可能保留它)

感谢任何帮助

Codepen Link

CODE



var timer = setInterval(function() {
  document.querySelector(".qs-timer-overlay").style.opacity = (document.querySelector(".qs-timer-overlay").style.opacity * 1) + 0.1;
  if (document.querySelector(".qs-timer-overlay").style.opacity * 1 == 1) {
    clearInterval(timer);
  }
}, 1000);

.qs-main-header .qs-timer {
  padding: 13px 10px;
  min-width: 130px;
  text-align: center;
  display: inline-block;
  background-color: #dd8b3a;
  color: #FFF;
  font-size: 20px;
  border-radius: 50px;
  text-transform: uppercase;
  float: right;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.qs-main-header .qs-timer-overlay {
  z-index: 1;
  width: 10%;
  max-width: 100%;
  position: absolute;
  height: 100%;
  top: 0;
  left: 0;
  background-color: #c7543e;
  opacity: 0.0;
  /* border-radius: 50px 50px 0px 50px; */
}
.qs-main-header .qs-timer-content {
  z-index: 2;
  position: relative;
}
.scale-transition {
  -webkit-transition: all 1s;
  transition: all 1s;
}

<div class="qs-main-header">
  <div class="qs-timer scale-transition ng-hide" ng-show="visibility.timer">
    <div class="scale-transition qs-timer-overlay"></div>
    <div class="qs-timer-content ng-binding">0 <span class="ng-binding">Sec(s)</span>
    </div>
  </div>
</div>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:13)

实际上,当转换发生时,border-radius没有得到尊重。这是因为为加速渲染创建了合成图层,可以通过查看以下文章来解释:

为什么在禁用转换时问题不会发生?

  • 当样式发生变化时,不会满足任何需要创建合成图层的条件(即没有动画或过渡或3D变换等):
    • 没有合成层,因此整个区域似乎都会在每次更改时重新粉刷。由于完全重画发生没有问题。
  • 启用&#34; Show paint rects&#34;后,查看以下代码段(全屏模式)和&#34;显示合成图层边框&#34;从Dev工具中观察以下内容:
    • 不会创建带橙色边框的区域(合成图层)。
    • 每次通过将焦点设置在其中一个a标签上来修改样式时,整个区域都会重新绘制(红色或绿色闪烁区域)。

&#13;
&#13;
.outer {
  position: relative;
  height: 100px;
  width: 100px;
  margin-top: 50px;
  border: 1px solid red;
  overflow: hidden;
}
.border-radius {
  border-radius: 50px;
}
.inner {
  width: 50px;
  height: 50px;
  background-color: gray;
  opacity: 0.75;
}
a:focus + .outer.border-radius > .inner {
  transform: translateX(50px);
  height: 51px;
  opacity: 0.5;
}
&#13;
<a href='#'>Test</a>
<div class='outer border-radius'>
  <div class='inner'>I am a strange root.
  </div>
</div>
&#13;
&#13;
&#13;

为什么添加转换会产生问题?

  • 初始渲染没有合成图层,因为元素上还没有过渡。查看下面的代码段并注意如何在代码段运行时发生绘画(红色或绿色闪烁区域),但不会创建合成图层(带橙色边框的区域)。
  • 转换开始时,Chrome会将某些属性(如不透明度,转换等)转换为不同的合成图层。请注意,只要在其中一个锚标记上设置焦点,就会显示两个带橙色边框的区域。这些是创建的合成图层。
  • 正在进行图层分割以加速渲染。正如HTML5 Rocks文章中所提到的,通过更改合成图层的属性来应用不透明度和变换更改,并且不会重新绘制。
  • 在转换结束时,重新绘制会将所有图层合并回单个图层,因为合成图层不再适用(基于创建图层的条件)。

&#13;
&#13;
.outer {
  position: relative;
  height: 100px;
  width: 100px;
  margin-top: 50px;
  border: 1px solid red;
  overflow: hidden;
}
.border-radius {
  border-radius: 50px;
}
.inner {
  width: 50px;
  height: 50px;
  background-color: gray;
  transition: all 1s 5s;
  /*transition: height 1s 5s; /* uncomment this to see how other properties don't create a compositing layer */
  opacity: 0.75;
}
a:focus + .outer.border-radius > .inner {
  transform: translateX(50px);
  opacity: 0.5;
  /*height: 60px; */
}
&#13;
<a href='#'>Test</a>
<div class='outer border-radius'>
  <div class='inner'>I am a strange root.
  </div>
</div>
&#13;
&#13;
&#13;

这说明当合并图层并完成重新绘制时,父图案上的border-radius也会得到应用和尊重。但是,在转换期间,仅改变合成层的属性,因此该层似乎不会意识到其他层的属性,因此不会尊重父级的边界半径。

我认为这是因为渲染图层的方式有效。每一层都是一个软件位图,因此它等同于拥有一个圆形图像,然后在它上面放置一个div。这显然不会导致任何内容裁剪。

this bug thread中的评论似乎也证实了当不再需要单独的图层时会发生重绘。

  

如果&#34;获得自己的图层,我们想重新绘制&#34;将要改变

注意:虽然它们是针对Chrome的,但我认为其他行为也应该类似。

解决方案是什么?

解决方案似乎是为父(.qs-timer)元素创建单独的堆叠上下文。创建单独的堆叠上下文似乎导致为父级创建单独的合成层,这解决了问题。

正如BoltClock在this answer中所提到的,以下任何一个选项都会为父级创建一个单独的堆叠上下文,并且执行其中一个似乎可以解决问题。

  • 将父z-index上的.qs-timer设置为自动以外的任何内容。

    &#13;
    &#13;
    var timer = setInterval(function() {
      document.querySelector(".qs-timer-overlay").style.opacity = (document.querySelector(".qs-timer-overlay").style.opacity * 1) + 0.1;
      if (document.querySelector(".qs-timer-overlay").style.opacity * 1 == 1) {
        clearInterval(timer);
      }
    }, 1000);
    &#13;
    .qs-main-header .qs-timer {
      padding: 13px 10px;
      min-width: 130px;
      text-align: center;
      display: inline-block;
      background-color: #dd8b3a;
      color: #FFF;
      font-size: 20px;
      border-radius: 50px;
      text-transform: uppercase;
      float: right;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      z-index: 1; /* creates a separate stacking context */
    }
    .qs-main-header .qs-timer-overlay {
      z-index: 1;
      width: 10%;
      max-width: 100%;
      position: absolute;
      height: 100%;
      top: 0;
      left: 0;
      background-color: #c7543e;
      opacity: 0.0;
      /* border-radius: 50px 50px 0px 50px; */
    }
    .qs-main-header .qs-timer-content {
      z-index: 2;
      position: relative;
    }
    .scale-transition {
      -webkit-transition: all 1s;
      transition: all 1s;
    }
    &#13;
    <div class="qs-main-header">
      <div class="qs-timer scale-transition ng-hide" ng-show="visibility.timer">
        <div class="scale-transition qs-timer-overlay"></div>
        <div class="qs-timer-content ng-binding">0 <span class="ng-binding">Sec(s)</span>
        </div>
      </div>
    </div>
    &#13;
    &#13;
    &#13;

  • opacity设置为小于1的任何内容。我在下面的代码段中使用了0.99,因为它不会造成任何视觉差异。

    &#13;
    &#13;
    var timer = setInterval(function() {
      document.querySelector(".qs-timer-overlay").style.opacity = (document.querySelector(".qs-timer-overlay").style.opacity * 1) + 0.1;
      if (document.querySelector(".qs-timer-overlay").style.opacity * 1 == 1) {
        clearInterval(timer);
      }
    }, 1000);
    &#13;
    .qs-main-header .qs-timer {
      padding: 13px 10px;
      min-width: 130px;
      text-align: center;
      display: inline-block;
      background-color: #dd8b3a;
      color: #FFF;
      font-size: 20px;
      border-radius: 50px;
      text-transform: uppercase;
      float: right;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      opacity: 0.99; /* creates a separate stacking context */
    }
    .qs-main-header .qs-timer-overlay {
      z-index: 1;
      width: 10%;
      max-width: 100%;
      position: absolute;
      height: 100%;
      top: 0;
      left: 0;
      background-color: #c7543e;
      opacity: 0.0;
      /* border-radius: 50px 50px 0px 50px; */
    }
    .qs-main-header .qs-timer-content {
      z-index: 2;
      position: relative;
    }
    .scale-transition {
      -webkit-transition: all 1s;
      transition: all 1s;
    }
    &#13;
    <div class="qs-main-header">
      <div class="qs-timer scale-transition ng-hide" ng-show="visibility.timer">
        <div class="scale-transition qs-timer-overlay"></div>
        <div class="qs-timer-content ng-binding">0 <span class="ng-binding">Sec(s)</span>
        </div>
      </div>
    </div>
    &#13;
    &#13;
    &#13;

  • 向元素添加transform。我在下面的代码段中使用了translateZ(0px),因为这也没有产生任何视觉差异。

    &#13;
    &#13;
    var timer = setInterval(function() {
      document.querySelector(".qs-timer-overlay").style.opacity = (document.querySelector(".qs-timer-overlay").style.opacity * 1) + 0.1;
      if (document.querySelector(".qs-timer-overlay").style.opacity * 1 == 1) {
        clearInterval(timer);
      }
    }, 1000);
    &#13;
    .qs-main-header .qs-timer {
      padding: 13px 10px;
      min-width: 130px;
      text-align: center;
      display: inline-block;
      background-color: #dd8b3a;
      color: #FFF;
      font-size: 20px;
      border-radius: 50px;
      text-transform: uppercase;
      float: right;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      transform: translateZ(0px) /* creates a separate stacking context */
    }
    .qs-main-header .qs-timer-overlay {
      z-index: 1;
      width: 10%;
      max-width: 100%;
      position: absolute;
      height: 100%;
      top: 0;
      left: 0;
      background-color: #c7543e;
      opacity: 0.0;
      /* border-radius: 50px 50px 0px 50px; */
    }
    .qs-main-header .qs-timer-content {
      z-index: 2;
      position: relative;
    }
    .scale-transition {
      -webkit-transition: all 1s;
      transition: all 1s;
    }
    &#13;
    <div class="qs-main-header">
      <div class="qs-timer scale-transition ng-hide" ng-show="visibility.timer">
        <div class="scale-transition qs-timer-overlay"></div>
        <div class="qs-timer-content ng-binding">0 <span class="ng-binding">Sec(s)</span>
        </div>
      </div>
    </div>
    &#13;
    &#13;
    &#13;

前两种方法比第三种方法更优选,因为第三种方法仅适用于支持CSS转换的浏览器。

答案 1 :(得分:1)

是的,将opacity: 0.99;添加到.qs-timer问题将会修复。

不透明度时:1或不定义:
在这种特殊情况下,没有涉及透明度,因此gfx可以避免做昂贵的事情。

如果不透明度:0.99:
nsIFrame::HasOpacity()确定存在不透明度,因此gfx包含有价值的内容。 (喜欢opacityborder-radius

如需更多帮助Special case opacity:0.99 to treat it as opacity:1 for graphics,此故障单并未提供我们实际目标的意见,而是提供有关CSS内部情况的想法。