skew() 函数深入

skew() function in depth

我真的需要了解 skew(xdeg) 函数是如何工作的所有研究似乎都没有解释 x 角如何影响其他点并像那样扭曲它,我需要知道是否有任何数学公式或一种能够预期使用特定度数的结果的方法。

ps。我已经阅读了大量的文档,其中最好的一个是 DevDocs,它说

This transformation is a shear mapping (transvection) that distorts each point within an element by a certain angle in the horizontal and vertical directions. The coordinates of each point are modified by a value proportionate to the specified angle and the distance to the origin; thus, the farther from the origin a point is, the greater will be the value added it.

但没有进一步解释给定角度将如何影响元素中的那些点。

在 SVG 书中,它通过说它按特定值推动水平线或垂直线来解释倾斜,但我不明白 deg 值如何转换为偏移量

应用在<angle>上的mathematical operation就是tan(<angle>)。然后将其插入到转换矩阵中。

好的,这并没有真正深入 skew,也没有说明为什么使用角度而不是数字因子有意义。因此,让我们以下面的 ASCII 示例为例,显示仅 x 偏斜。

   skewX(0)            skewX(45deg)
_|         |_         _|         |_ => original box markers
  a o o o o         a o o o o    
  b o o o o           b o o o o
  c o x o o             c o x o o   <-- this line didn't move
  d o o o o               d o o o o
  e o o o z                 e o o o z
 |         |           |         |

因此,如果我们应用 tan(45deg),它会为我们提供 1 的 skewX 因子。
这意味着所有水平线都将位移 1 * 它们到变换原点的距离。

在上面的例子中,变换原点是 5*5 image.
的中心 (x) 所以第一条像素线 (a o o o o) 距离原点负两个像素,它将在左侧平移 2px。
最后一行 (e o o o z) 距离原点 +2px,将在右侧平移 2px。
原点上的中间线 (c o x o o) 不会受到此变换的影响。

好吧,但这仍然不能解释为什么要考虑角度而不是因素...

角度符号也很有意义,因为我们还可以解释我们的示例,因为我们将每列的中心点用作锚点旋转 45 度。

即使这只是我的推测,角度也有额外的好处,允许 skewN(90deg) 无法用数字因子表示的状态。

要了解 skew 的工作原理,让我们将其与另一个使用角度的转换进行比较。

这是一个旋转的例子,我们将变换原点设为 top left,然后从那里旋转 45deg:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:rgba(255,0,0,0.5);
  transform-origin:top left;
  transform:rotate(45deg);
}
<div class="box">
  <div></div>
</div>

对于这个例子,找到角度及其工作原理在某种程度上是微不足道的:

现在让我们举同样的例子,将旋转元素的高度减小到一个小值:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:3px;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:rotate(45deg);
}
<div class="box">
  <div></div>
</div>

这就像我们有一条旋转线。现在让我们用倾斜替换旋转:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:3px;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skewY(45deg);
}
<div class="box">
  <div></div>
</div>

如果我们比较这两个结果,我们会注意到我们在这两种情况下都有某种旋转,但在倾斜变换时大小不同:

现在更清楚倾斜如何与角度一起工作了。变换是一种依赖于角度来定义这种扭曲的扭曲。这是一个更好的例子:

蓝色是我们的初始元素,十字是变换原点,黄色是角度。如果我们进行旋转,我们将获得 宽度保持不变 的红线。如果我们进行倾斜,我们将获得橙色线,其中 宽度将改变 并且考虑到插图它将等于 W / cos(angle) 其中 W 是我们的初始宽度(在我们之前的例子中 cos(45deg) = 1 / sqrt(2) 所以我们将有 W * sqrt(2))。


现在我们的初始正方形如何处理倾斜?

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skewY(45deg);
}
<div class="box">
  <div></div>
</div>

它的行为与我们之前逐行描述的完全一样。如果我们在另一个方向上应用倾斜,我们也会得到相同的结果:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skewX(45deg);
}
<div class="box">
  <div></div>
</div>

应用相同的逻辑,但应用于垂直线并考虑高度。作为旁注,skewX(V)skew(V)ref.

相同

现在如果我们在两个方向上应用倾斜:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skew(45deg,10deg);
}
<div class="box">
  <div></div>
</div>

这就像我们先应用 skewX 来扭曲垂直线,然后我们应用 skewY 到新形状来扭曲水平线(或相反)。这是一个动画来说明 skew(45deg,45deg):

的神奇结果

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:top left;
  transform:skew(45deg,10deg);
  animation:change 5s infinite alternate linear;
}
@keyframes change {
  from {
    transform:skew(0deg,0deg);
  }
  50% {
    transform:skew(45deg,0deg);
  }
  to {
    transform:skew(45deg,45deg);
  }
}
<div class="box">
  <div></div>
</div>

那么产地呢?转换不会发生任何变化,只有引用会发生变化。也就是说,不动点会移动:

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform-origin:center;
  transform:skew(45deg,10deg);
  animation:change 5s infinite alternate linear;
}
@keyframes change {
  from {
    transform:skew(0deg,0deg);
  }
  50% {
    transform:skew(45deg,0deg);
  }
  to {
    transform:skew(45deg,45deg);
  }
}
<div class="box">
  <div></div>
</div>

我们可能还会注意到,如果我们在一个方向上进行倾斜,则只会考虑 transform-origin 中的一个参数。

因此对于 skewXtransform-origin: X Y 将与 X 的值相同。这在某种程度上解释了 逐行 转换,因为当我们在线时我们有一个维度。

.box {
  margin:50px;
  width:200px;
  height:200px;
  background:blue;
}
.box > div {
  height:100%;
  width:100%;
  background:red;
  transform:skewX(45deg);
  animation:change 5s infinite alternate linear;
}
@keyframes change {
  from {
    transform-origin:0 0;
  }
  50% {
    transform-origin:100% 0;/*nothing will happen between 0 and 50%*/
  }
  to {
    transform-origin:100% 100%;
  }
}
<div class="box">
  <div></div>
</div>

更深入

现在让我们考虑矩阵计算以了解它的使用方式以及如何使用 tan(angle)

如果我们参考 the documentation 我们有:

该矩阵用于根据初始元素的坐标逐点定义变换后元素的坐标。考虑到这个定义,我们将有这些方程

Xf = Xi + Yi * tan(ax)
Yf = Xi * tan(ay) + Yi

如果我们只考虑 skewY 很明显 ax 将是 0 因此 tan(0) 将是 0X 不会' t 改变了我们第一个例子的情况,我们只在 Y 轴上有失真(如果我们只应用 skewY,逻辑相同)。

现在,为什么我们有 Yf = Xi * tan(ay) + Yi

让我们重温之前的例子:

绿点是Xi,Yi定义的初始点,红点是Xf,Yf定义的变换点。 Xf=Xi 很简单,两点之间的距离将是 Yf-Yi.

考虑到插图,我们可以清楚地说 tan(ay) = (Yf-Yi)/Xi = (Yf-Yi)/Xf 因此我们将有:

Xf = Xi 
Yf = Xi * tan(ay) + Yi

如果我们向另一个方向倾斜,我们应用相同的逻辑。