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

use*_*463 8 html javascript css css3 css-animations

如果您看到我共享的代码示例,您可以看到框外的叠加层.我将问题追溯到transition属性.

我想删除div之外的内容.溢出不按预期工作.(删除transition作品,但如果可能,我想保留它)

任何帮助表示赞赏

Codepen链接

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);
Run Code Online (Sandbox Code Playgroud)
.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;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

Har*_*rry 13

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


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

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

.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;
}
Run Code Online (Sandbox Code Playgroud)
<a href='#'>Test</a>
<div class='outer border-radius'>
  <div class='inner'>I am a strange root.
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)


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

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

.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; */
}
Run Code Online (Sandbox Code Playgroud)
<a href='#'>Test</a>
<div class='outer border-radius'>
  <div class='inner'>I am a strange root.
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

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

我认为这是因为渲染图层的方式.每一层都是一个软件位图,所以它有点像一个圆形图像,然后放在div它上面.这显然不会导致任何内容裁剪.

这个bug线程中的注释似乎也证实了当不再需要单独的层时会发生重绘.

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

注意:虽然它们是特定于Chrome的,但我认为其他行为也应该类似.


解决办法是什么?

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

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

  • z-index父级设置为.qs-timer除auto之外的任何内容.

    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);
    Run Code Online (Sandbox Code Playgroud)
    .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;
    }
    Run Code Online (Sandbox Code Playgroud)
    <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>
    Run Code Online (Sandbox Code Playgroud)

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

    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);
    Run Code Online (Sandbox Code Playgroud)
    .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;
    }
    Run Code Online (Sandbox Code Playgroud)
    <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>
    Run Code Online (Sandbox Code Playgroud)

  • 添加transform到元素.我translateZ(0px)在下面的片段中使用过,因为这也不会产生任何视觉差异.

    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);
    Run Code Online (Sandbox Code Playgroud)
    .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;
    }
    Run Code Online (Sandbox Code Playgroud)
    <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>
    Run Code Online (Sandbox Code Playgroud)

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