如何解决呈现为黑色方块的动画元素(Chrome 错误)?

How to work around animated element rendered as a black square (Chrome bug)?

Chromium 版本 75.0.3770.100(官方构建)Arch Linux(64 位)。
在 Brave 的 Android 上也观察到(也基于 Chromium 75)。

我正在制作一个填充有白色渐变的旋转正方形:

.spinning {
  animation-name: spinning;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  width: 100px;
  height: 100px;
  background-image: radial-gradient(farthest-corner at 40% 40%, #fff, #f7f7f7 50%, #e8e8e8 75%, #d1d1d1 100%);
  backface-visibility: hidden;
}

@keyframes spinning {
  0% { transform: rotate3d(1, -1, 0, -180deg); }
  100% { transform: rotate3d(1, -1, 0, 180deg); }
}
<div class="spinning"></div>

这在 Firefox 上运行良好。但是,在 Chrome 上,我最初看到的是 黑色 正方形而不是白色正方形。就好像 Chrome 忘记渲染元素的图层一样。此外,旋转轴略微偏离中心。当我右击方块并选择"Inspect"时,它突然意识到它的方式错误并变成白色。

看起来我 运行 进入了 issue 966019,它出现在 Chrome 75 或可能是 74 并且已经确认和分配,但尚未修复。

值得注意的是:

解决方法:

由于所有这些都有不良副作用,我正在寻找更好的解决方法。

另一种解决方法是在元素的 pseudo-element content 属性:

上触发动画

.spinning {
  animation-name: spinning;
  animation-duration: 2s;
  animation-delay: 0s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  width: 100px;
  height: 100px;
  backface-visibility: hidden;
  animation-fill-mode: forwards;
  background-image: radial-gradient(farthest-corner at 40% 40%, #fff, #f7f7f7 50%, #e8e8e8 75%, #d1d1d1 100%);

}
.spinning::after {
  content: "";
  animation: trigger-paint .1s forwards 1;
}
@keyframes spinning {
  0% { transform: rotate3d(1, -1, 0, -180deg); }
  100% { transform: rotate3d(1, -1, 0, 180deg); }
}
@keyframes trigger-paint {
  0% {content: ""}
  100% {content: none}
}
<div class="spinning"></div>

但由于这里的技巧是强制重绘,我担心这会带来巨大的性能影响(根据我的开发工具,它确实会重新启动动画很多次,即使它已设置为开始一次)。

最终通过不依赖 backface-visibility 而是自己制作动画 visibility 解决了这个问题:

.spinning {
  animation-name: spinning, hide-backface;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-timing-function: linear, step-start;
  width: 100px;
  height: 100px;
  background-image: radial-gradient(farthest-corner at 40% 40%, #fff, #f7f7f7 50%, #e8e8e8 75%, #d1d1d1 100%);
}

@keyframes spinning {
  0% { transform: rotate3d(1, -1, 0, -180deg); }
  100% { transform: rotate3d(1, -1, 0, 180deg); }
}

@keyframes hide-backface {
  0% { visibility: hidden; }
  25% { visibility: hidden; }
  75% { visibility: visible; }
  100% { visibility: hidden; }
}
<div class="spinning"></div>

另一种解决方案是考虑使用伪元素来创建两侧,这样就不会出现错误,并且可以轻松地单独管理每一侧。

.spinning {
  animation-name: spinning;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  width: 100px;
  height: 100px;
  position: relative;
  transform-style:preserve-3d;
}
.spinning:before,
.spinning:after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  backface-visibility: hidden;
}
.spinning:before {
  background-image: radial-gradient(farthest-corner at 40% 40%, #fff, #f7f7f7 50%, #e8e8e8 75%, #d1d1d1 100%);
}
.spinning:after {
  transform: rotateY(180deg);
  background:rgba(255,0,0,0.5);
}

@keyframes spinning {
  0% {
    transform: rotate3d(1, -1, 0, -180deg);
  }
  100% {
    transform: rotate3d(1, -1, 0, 180deg);
  }
}
<div class="spinning"></div>