矩阵不等于 css 变换动画中的平移和旋转组合?

matrix not equal to translate and rotate combination in css transform animation?

@keyframes gray {
  0% { transform: matrix(1, 0, 0, 1, 0, 0) }
  100% { transform: matrix(-1, 0, 0, -1, 20, 20) }
}
@keyframes lightblue {
  0% { transform: translate(10px, 10px) rotate(0deg) translate(-10px, -10px); }
  100% { transform: translate(10px, 10px) rotate(180deg) translate(-10px, -10px); }
}
.gray {
  float: left;
  margin-left: 50px;
  width: 20px;
  height: 20px;
  background: gray;
  transform-origin: 0px 0px;
  animation: gray linear 1s infinite;
}
.lightblue {
  float: left;
  margin-left: 50px;
  width: 20px;
  height: 20px;
  background: lightblue;
  transform-origin: 0px 0px;
  animation: lightblue linear 1s infinite;
}
  <div class="gray"></div>
  <div class="lightblue"></div>

据我所知

transform: matrix(1, 0, 0, 1, 0, 0);

等于

transform: translate(10px, 10px) rotate(0deg) translate(-10px, -10px);

transform: matrix(-1, 0, 0, -1, 20, 20)

等于

transform: translate(10px, 10px) rotate(180deg) translate(-10px, -10px);

当我直接对元素使用上述 css 规则时,一切正常。 但是在我在关键帧中使用上面的 css 规则之后,事情就出错了。 灰色元素的旋转角度与浅蓝色元素不同

我测试了chrome71

中的代码

问题在于浏览器将如何处理插值。两个矩阵都很好,它们与定义的变换相同,但两者之间的插值不同。

使用 forwards 而不是 infinite 可以看到两者将以相同的状态开始和结束:

@keyframes gray {
  0% { transform: matrix(1, 0, 0, 1, 0, 0) }
  100% { transform: matrix(-1, 0, 0, -1, 20, 20) }
}
@keyframes lightblue {
  0% { transform: translate(10px, 10px) rotate(0deg) translate(-10px, -10px); }
  100% { transform: translate(10px, 10px) rotate(180deg) translate(-10px, -10px); }
}
.gray {
  float: left;
  margin-left: 50px;
  width: 20px;
  height: 20px;
  background: gray;
  transform-origin: 0px 0px;
  animation: gray linear 2s 0.5s forwards;
  border-right:2px solid;
}
.lightblue {
  float: left;
  margin-left: 50px;
  width: 20px;
  height: 20px;
  background: lightblue;
  transform-origin: 0px 0px;
  animation: lightblue linear 2s 0.5s forwards;
  border-right:2px solid;
}
<div class="gray"></div>
  <div class="lightblue"></div>

基本上,矩阵会先分解为变换,然后再进行插值。所以第一个 matrix(1, 0, 0, 1, 0, 0) 即身份将被转换为空转换(例如 scale(1,1)rotate(0))而不是像你想象的那样 translate(10px, 10px) rotate(0deg) translate(-10px, -10px) 。那么第二个matrix(-1, 0, 0, -1, 20, 20)可以转化为scale(-1,-1) translate(-20px,-20px)。同样不会是 translate(10px, 10px) rotate(180deg) translate(-10px, -10px).

现在很明显,两个动画的插值(中间状态)将不相同。这是因为浏览器不会使用您用于定义矩阵的相同转换。理论上,有无限多种组合,浏览器会使用自己的算法找到他要使用的一种,不一定是你定义的那种。

您可以查看此 link 了解更多详情:https://drafts.csswg.org/css-transforms/#interpolation-of-transforms

这是一个我们如何使两者相同的示例:

@keyframes gray {
  0% { transform: matrix(1, 0, 0, 1, 0, 0) }
  100% { transform: matrix(-1, 0, 0, -1, 20, 20) }
}
@keyframes lightblue {
  0% { transform: scale(1,1) }
  100% { transform:scale(-1,-1) translate(-20px, -20px)  ; }
}
.gray {
  float: left;
  margin-left: 50px;
  width: 20px;
  height: 20px;
  background: gray;
  transform-origin: 0px 0px;
  animation: gray linear 2s 0.5s infinite;
  border-right:2px solid;
}
.lightblue {
  float: left;
  margin-left: 50px;
  width: 20px;
  height: 20px;
  background: lightblue;
  transform-origin: 0px 0px;
  animation: lightblue linear 2s 0.5s infinite;
  border-right:2px solid;
}
<div class="gray"></div>
  <div class="lightblue"></div>