CSS3转换顺序很重要:最先操作

Bas*_*asj 25 css transform css3 css-transforms

当我们使用CSS3时transform: operation1(...) operation2(...),首先完成哪一个?

第一次操作似乎是最右边的操作.,即此处operation2已完成operation1.只是为了确定,这是真的吗?

注意:我在某些地方读过一件事,反之亦然(答案,互联网上的文章),这就是问题所在.

Bas*_*asj 31

是的,完成的第一个操作是右边最多的一个操作,即operation2之前完成的操作operation1.

这是文档:http://www.w3.org/TR/css-transforms-1/但我还没有找到关于这个的段落.


例1

这里首先完成缩放,然后垂直翻译100px(如果先完成翻译,缩放将使500px的平移!)

#container { 
  	position: absolute; 
  	transform: translate(0,100px) scale(5); 
  	transform-origin: 0 0; }
Run Code Online (Sandbox Code Playgroud)
<div id="container"><img src="https://i.stack.imgur.com/xb47Y.jpg"></img></div>
Run Code Online (Sandbox Code Playgroud)

例2

这里首先完成翻译,然后进行缩放(缩放之后完成缩放,使翻译看起来像500px翻译!)

#container { 
  	position: absolute; 
  	transform: scale(5) translate(0,100px); 
  	transform-origin: 0 0; }
Run Code Online (Sandbox Code Playgroud)
<div id="container"><img src="https://i.stack.imgur.com/xb47Y.jpg"></img></div>
Run Code Online (Sandbox Code Playgroud)

  • 还注意到[关于CSS转换的MDN文章]中的这一行(https://developer.mozilla.org/en-US/docs/Web/CSS/transform):"转换函数按从左到右的顺序相乘,意味着复合变换从右到左有效地应用." (3认同)
  • 这个答案是错误的。作为其他答案状态,它是从左到右完成的。该答案应删除。 (2认同)
  • @ T3rm1请运行代码段,您将自己看到它是正确的。 (2认同)
  • @JeffreyKlein如果运行我的示例1,您会看到scale(5)首先运行。然后将其向南平移100px。并非相反。如果相反,即先翻译,然后缩放x5,那么我们会看到100 * 5 = 500px白色。事实并非如此。**因此,我确认它是从右到左**,至少是根据平面转换的数学定义和此类操作的组成。如果您不同意,请提供另一个带有可运行代码段的答案,以便我们测试您的建议。 (2认同)
  • @JeffreyKlein 好吧,我现在看到你的困惑了。事实上,您所引用的句子证实了我的答案;)请参阅线性代数课程和函数的[组合](https://en.wikipedia.org/wiki/Function_composition)(将矩阵视为变换函数是相同的)飞机)。简而言之,这个想法是:当你写 `(g ∘ f)(x) = g(f(x))` 时,即使 g 在左边,你对输入 (x) 应用的第一个函数是f,然后 g。 (2认同)

Bal*_*alo 10

这在其他答案和评论中已经提到过,但在我看来没有得到足够的重视:简短的答案是两种方式都是有效的

这完全取决于您是否考虑将坐标附加到元素(从左到右)或基于初始元素位置(从右到左)固定到页面。

这是一篇文章,展示了与动画的区别(这使得它更容易理解):链接变换

以下是显示文章中的动画的片段:

html, body { height: 100%; }
body {
  background: #aaa;
  color: #000;
  font-family: Calibri,Candara,Segoe,"Segoe UI",Optima,Arial,sans-serif;
  overflow: hidden;
  margin: 0;
}
.info {
  text-align: center;
  font-family: Consolas,monaco,monospace;
  font-size: 20px;
  font-weight: bold;
  margin-bottom: 4px;
  color: #fff;
}
.split { white-space: nowrap; }
.side {
  display: inline-block;
  width: 50%;
}
.label {
  text-align: center;
  font-size: 20px;
}
.container {
  position: relative;
  font-size: 50px;
  margin: .6em auto 0;
  width: 0; height: 0;
  transform: translateX(-1em);
}
.ltr .object {
  position: absolute;
  left: 0; top: 0;
  width: 1em; height: 1em;
  margin: -.5em 0 0 -.5em;
  background: rgb(114,34,34);
  animation: ltrObj 5s infinite;
}
@keyframes ltrObj {
  from, 10% { transform: rotate( 0deg) translateX(0em); }
  40%       { transform: rotate(45deg) translateX(0em); }
  70%, to   { transform: rotate(45deg) translateX(2em); }
}
.object.shadow {
  animation: none;
  opacity: .2;
}

.ltr .axes {
  position: absolute;
  left: .5em; top: .5em;
  width: 1em; height: 1em;
  color: #111;
  box-sizing: border-box;
  border-left: 2px solid;
  border-top: 2px solid;
}
.ltr .axes::before, .ltr .axes::after {
  content: '';
  position: absolute;
  width: .2em; height: .2em;
  box-sizing: border-box;
  border-left: 2px solid;
  border-top: 2px solid;
  transform-origin: top left;
}
.ltr .axes::before { top: 100%; left: 0; margin-left: -1px; margin-top: 1px; transform: rotate(225deg); }
.ltr .axes::after { top: 0; left: 100%; margin-top: -1px; margin-left: 1px; transform: rotate(135deg); }

.rtl .axes {
  position: absolute;
  left: 0; top: 0;
  width: 2.5em; height: 2.3em;
  color: #111;
  box-sizing: border-box;
  border-left: 2px solid;
  border-top: 2px solid;
}
.rtl .axes::before, .rtl .axes::after {
  content: '';
  position: absolute;
  width: .2em; height: .2em;
  box-sizing: border-box;
  border-left: 2px solid;
  border-top: 2px solid;
  transform-origin: top left;
}
.rtl .axes::before { top: 100%; left: 0; margin-left: -1px; margin-top: 1px; transform: rotate(225deg); }
.rtl .axes::after { top: 0; left: 100%; margin-top: -1px; margin-left: 1px; transform: rotate(135deg); }

.rtl .object {
  position: absolute;
  left: 0; top: 0;
  width: 1em; height: 1em;
  margin: -.5em 0 0 -.5em;
  background: rgba(100,0,0,0.8);
  animation: rtlObj 5s infinite;
}
@keyframes rtlObj {
  from, 10% { transform: rotate( 0deg) translateX(0em); }
  40%       { transform: rotate( 0deg) translateX(2em); }
  70%, to   { transform: rotate(45deg) translateX(2em); }
}

.helper-mask {
  position: absolute;
  left: 0; top: 0;
  width: 3em; height: 3em;
  overflow: hidden;
}
.helper {
  position: absolute;
  left: 0; top: -2em;
  width: 0; height: 2em;
  margin-top: 2px;
  box-sizing: border-box;
  border: 2px solid #00c;
  border-left: none;
  border-radius: 0 100% 0 0;
  transform-origin: bottom left;
  animation: helper 5s infinite;
}
@keyframes helper {
  from, 10% { width: 0em; transform: rotate( 0deg); }
  40%       { width: 2em; transform: rotate( 0deg);}
  70%, to   { width: 2em; transform: rotate(45deg);}
}
Run Code Online (Sandbox Code Playgroud)
<div class="info">rotate(45deg) translateX(2em)</div>
<div class="split">
  <div class="side ltr">
    <div class="label">Left to Right</div>
    <div class="container">
      <div class="object shadow"></div>
      <div class="object">
        <div class="axes"></div>
      </div>
    </div>
  </div>
  <div class="side rtl">
    <div class="label">Right to Left</div>
    <div class="container">
        <div class="axes"></div>
        <div class="object"></div>
        <div class="helper-mask">
            <div class="helper"></div>
        </div>
    </div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

实际实现中使用从左到右还是从右到左都无关紧要,在创建动画时两者都同样有效,只要记住差异即可。

  • 这篇文章需要比现在更多的曝光。谢谢你!PS 基本上,这必须标记为答案。 (5认同)

Rob*_*era 5

转换从左到右执行。变换对应于矩阵运算,并且这些变换是从左到右执行的。

它背后有直觉,这不仅仅是规范中的字面意义(这里的第3点:https : //drafts.c​​sswg.org/css-transforms-1/#transform-rendering

这是一支可以尝试的笔:https : //codepen.io/monfera/pen/YLWGrM

说明:

每个变换步骤都建立自己的坐标系。所以

transform: translateX(500px);
Run Code Online (Sandbox Code Playgroud)

沿其父对象的X轴建立一个500px的新坐标系,该元素将在那里渲染。

同样,

background-color: blue;
transform: translateX(500px) rotate(60deg);
Run Code Online (Sandbox Code Playgroud)

首先沿着其父级的X轴(向右)建立一个新的坐标系500px,然后,在该坐标系中(已转换,但现在不相关了),它执行旋转。因此它将是一个向右500px的形状,并在适当位置旋转(围绕所谓的transform-origin在局部坐标系中解释的形状,默认的50%50%用于旋转是指围绕矩形的中心旋转,不过放在一边)。

倒序

background-color: orange;
transform: rotate(60deg) translateX(500px);
Run Code Online (Sandbox Code Playgroud)

首先建立一个新的坐标系,该坐标系相对于父级旋转60度,然后沿着当前旋转的坐标系的X轴平移100px,其方向实际上不是从文档(或用户)的全局视点右边)。因此,在这种情况下,就好像您先旋转纸张,然后沿着纸张的侧面(从原点(在本例中为左上角))将形状滑动500个单位一样。

在此处输入图片说明

要进行更高级的讨论,并了解如何在两个方向上直观地理解它,请查看组成转换 -CSS转换遵循乘法后模型,因此请查找标题为“将转换视为对本地进行转换的思考”的页面坐标框架”(尽管插图似乎有些偏离)

局部坐标系-乘后