在不同元素上添加动画时,不考虑边框半径和溢出

Border radius and overflow aren't respected when animation is added on a different element

我在 CSS3 中使用 transform 时出现奇怪的行为。

这是我的代码:

*, *:before, *:after {
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
}

.btn_exchange a {
    position: relative;
    text-decoration: none;
    display: block;
    width: 150px;
    float: left;
    color: #ffffff;
    font-size: 14px;
    background: #0ea2d3;
    box-shadow: 0 3px 0 0 rgba(7, 154, 190, 0.75);
    text-align: center;
    font-weight: bold;
}

@keyframes pulse {
    0% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.05);
    }
    100% {
        transform: scale(1);
    }
}

@-webkit-keyframes pulse {
    0% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.05);
    }
    100% {
        transform: scale(1);
    }
}

a.abc {
    z-index: 0;
    -webkit-animation: pulse 1s linear 0s infinite alternate;
    animation: pulse 1s linear infinite;
}

#box_avatar {
    position: relative;
    margin: 0 auto;
    -webkit-border-radius: 62.5px;
    -moz-border-radius: 62.5px;
    -ms-border-radius: 62.5px;
    -o-border-radius: 62.5px;
    border-radius: 62.5px;
    width: 125px;
    height: 125px;
    border: 2px solid #ccc;
    display: block;
    overflow: hidden;
}

#img_avatar {
    width: 125px;
    height: 125px;
    cursor: pointer;
    border-radius: 62.5px;
}

#bg_gray {
    background: #4c4747;
    width: 100%;
    position: absolute;
    bottom: 0;
    padding: 8px 0 10px 0;
    opacity: 0.8;
}

#bg_gray img {
    display: block;
    width: 20px;
    margin: 0 auto;
}
<div class="btn_exchange fl bad">
  <a class="button abc" href="#">Button</a>
</div>

<div id="box_avatar">
  <img id="img_avatar" src="http://i.imgur.com/O29DJOZ.jpg" alt="avatar" />
  <div id="bg_gray">
    <img src="http://i.imgur.com/m5qIRID.png" alt="btn_camera" />
  </div>
</div>

<div class="btn_exchange fl good">
  <a class="button abc" href="#">Button</a>
</div>

当我使用 .bad div(删除 .good div)时出现问题,然后包含相机图标的灰色背景不在圆形图像。

如果我删除 CSS 中的动画 transform,按钮将不再闪烁,但灰色背景将位于圆形图像内。

有人知道这是什么以及如何解决吗?

我看了看,不明白为什么会这样,所以如果跳过 img 元素并使用背景图片代替可以吗?

如果是这样,这里有一个有效的示例。

另一种选择是组合 backgroundpseudo 而不是 img。这将为您提供更清晰的 html 结构并解决您的问题。

*, *:before, *:after {
    box-sizing: border-box;
}

.btn_exchange a {
    position: relative;
    text-decoration: none;
    display: block;
    width: 150px;
    float: left;
    color: #ffffff;
    font-size: 14px;
    background: #0ea2d3;
    box-shadow: 0 3px 0 0 rgba(7, 154, 190, 0.75);
    text-align: center;
    font-weight: bold;
}

@keyframes pulse {
    0% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.05);
    }
    100% {
        transform: scale(1);
    }
}

@-webkit-keyframes pulse {
    0% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.05);
    }
    100% {
        transform: scale(1);
    }
}

a.abc {
    z-index: 0;
    animation: pulse 1s linear infinite;
}

#box_avatar {
    position: relative;
    margin: 0 auto;
    border-radius: 62.5px;
    width: 125px;
    height: 125px;
    border: 2px solid #ccc;
    display: block;
    overflow: hidden;
    background: url(http://i.imgur.com/O29DJOZ.jpg);
    cursor: pointer;
}

#bg_gray {
    bottom: 0;
    left: 0;
    width: 100%;
    height: 30px;
    position: absolute;
    overflow: hidden;
    cursor: auto;
}
#bg_gray:before {
    content: "";
    background: #4c4747;
    width: 100%;
    height: 125px;
    bottom: 0;
    position: absolute;
    opacity: 0.8;
    border-radius: 62.5px;
}
#bg_gray:after {
    content: "";
    width: 100%;
    height: 30px;
    bottom: 0;
    position: absolute;
    background: url(http://i.imgur.com/m5qIRID.png) center center no-repeat;
    background-size: 20px;
}
<div class="btn_exchange fl bad">
  <a class="button abc" href="#">Button</a>
</div>

<div id="box_avatar">
  <div id="bg_gray"></div>
</div>

<div class="btn_exchange fl good">
  <a class="button abc" href="#">Button</a>
</div>

这个问题与那个的问题很相似。带有相机图标的灰色框不包含在圆圈内(未被圆圈裁剪)的原因是图层的创建方式和浏览器执行加速渲染的方式。您可以在我之前链接的答案中找到更多相关信息。

解法:

您的问题的解决方案是通过为它设置更高的 z-index 值来将脉冲按钮移动到更高的层。在下面的代码片段中,我将其设置为 1,您可以看到它解决了问题。

*, *:before, *:after {
  box-sizing: border-box;
}
.btn_exchange a {
  position: relative;
  display: block;
  float: left;
  width: 150px;
  color: #ffffff;
  font-size: 14px;
  text-decoration: none;
  text-align: center;
  font-weight: bold;
  background: #0ea2d3;
  box-shadow: 0 3px 0 0 rgba(7, 154, 190, 0.75);
}
@keyframes pulse {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
  100% {
    transform: scale(1);
  }
}
a.abc {
  z-index: 1;
  animation: pulse 1s linear infinite;
}
#box_avatar {
  position: relative;
  display: block;
  width: 125px;
  height: 125px;
  margin: 0 auto;
  border-radius: 62.5px;
  border: 2px solid #ccc;
  overflow: hidden;
}
#img_avatar {
  width: 125px;
  height: 125px;
  border-radius: 62.5px;
  cursor: pointer;
}
#bg_gray {
  position: absolute;
  width: 100%;
  bottom: 0;
  padding: 8px 0 10px 0;
  background: #4c4747;
  opacity: 0.8;
}
#bg_gray img {
  display: block;
  width: 20px;
  margin: 0 auto;
}
<div class="btn_exchange fl bad">
  <a class="button abc" href="#">Button</a>
</div>

<div id="box_avatar">
  <img id="img_avatar" src="http://i.imgur.com/O29DJOZ.jpg" alt="avatar" />
  <div id="bg_gray">
    <img src="http://i.imgur.com/m5qIRID.png" alt="btn_camera" />
  </div>
</div>

<div class="btn_exchange fl good">
  <a class="button abc" href="#">Button</a>
</div>

#box_avatar 应用 z-index 也可以解决问题。


原因:

渲染和合成很难解释,但以下是当没有 z-indexz-index: 0 设置为 a.abc 时会发生的情况:

  • a.abc 获得自己的渲染和合成层,因为它具有动画变换和显式定位属性。
  • this article 中解释了渲染和合成层的创建过程。通过在开发工具中启用 "Show Paint Rects" 和 "Show composited layer borders" 可以看到这些层。
  • #box_avatar#bg_gray 也有自己的合成层。 #box_avatar 似乎得到一个单独的层,因为它有一个等于或低于 z-index 的前一个兄弟。
  • 我无法准确指出为什么 #bg_gray 得到一个单独的层,但它似乎主要是因为 z-index: auto 如何创建一个单独的堆栈上下文。 (Source - W3C Spec)

当为 #box_avatar#bg_gray 创建了不同的层并将它们一层一层地放置时,#bg_gray 并不完全 #box_avatar 等不尊重 overflowborder-radius。这有点像把两层纸一层叠起来。


解法详解:

z-index: 1 分配给 a.abc 元素时:

  • a.abc 有自己的渲染和合成层,因为它有一个动画变换。
  • a.abc 的容器也获得了它的层,因为它有一个具有合成层的子层。
  • #box_avatar#bg_gray 均未获得单独的合成层,因为它们不符合为获得合成层而定义的任何条件。

z-index: 0 分配给 a.abc 并且 z-index: 1 分配给 #box_avatar 时:

  • a.abc 有自己的渲染和合成层,因为它有动画变换
  • a.abc 的容器也得到了它的层,因为它有一个有合成层的子层
  • #box_avatar 有自己的渲染和合成层,因为它有一个同级(a.abc 元素的容器),它的合成层较低 z-index
  • #bg_gray 成为 #box_avatar 元素层的一部分,没有单独的层。

在上述两种情况下,因为 #box_avatar#bg_gray 没有单独的图层,所以它们是一起绘制的,所以 #bg_gray 知道在哪里裁剪.