繁体   English   中英

在 CSS 中将 transform-origin 移回元素的中心

[英]Move transform-origin back to the center of the element in CSS

当 CSS 元素从它们原来的位置被转换出来时, transform-origin不会随之移动; 使所有后续变换和旋转仍然源自其原始transform-origin (下面的示例)。

我知道有一种方法可以解决这个问题……那就是继续将所有新变换添加到先前变换的右侧。 像这样: transform: translateY ( -5rem ) rotate( 45deg ) translateY( -10rem ) rotate( 15deg )...等等。这似乎总是根据需要从当前元素的中心开始新的变换。

问题

当您使用这种技术根据用户输入转换元素时,您将不断向 DOM 添加转换……无休止地。 占用大量内存并导致其他不需要的滑动效果(可能)。

这是一个动画,展示了每次变换后变换transform-origin如何不移动到元素的中心:

 'use strict'; function firstRotation() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.innerHTML = 'First, the V is rotated around it\\'s central axis.\\ The <b>transform-origin</b> is centered.'; v.classList.add( 'first-rotation' ); status.classList.add( 'update' ); }, 1000 ); } function firstTranslation() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.innerHTML = 'Next, the element is translated forward in it\\'s \\ current orientation. The <b>transform-origin</b> stays\\ behind where it was.'; v.classList.remove( 'first-rotation' ); v.classList.add( 'first-translation' ); }, 6000 ); } function info() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.innerHTML = 'This next animation is where it\\'s evident that\\ the <b>transform-origin</b> is no longer centered, but\\ back where it was at the beginning of these transforms'; }, 11000 ); } function lastRotation() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.innerHTML = 'This last rotation is far wider than desired because the\\ transform origin is back where it started.' v.classList.remove( 'first-translation' ); v.classList.add( 'last-rotation' ); }, 16000 ); } function end() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.classList.remove( 'update' ); }, 21000 ); } function start() { firstRotation(); firstTranslation(); info(); lastRotation(); end(); } start();
 /* / / / / / / / / / / / / / ANIMATION DEFINITIONS / / / / / / / / / / / / / */ .first-rotation, .first-translation, .update, .last-rotation { animation-duration: 5s; animation-timing-function: ease-in-out; animation-fill-mode: forwards; } .first-rotation { animation-name: first-rotation; } .first-translation { animation-name: first-translation; } .update { animation-name: update; animation-iteration-count: infinite; } .last-rotation { animation-name: last-rotation; } /*/ / / / / / / / / / / / / / ANIMATION KEYFRAMES / / / / / / / / / / / / / /*/ @keyframes first-rotation { 100% { transform: rotate( 315deg ); } } @keyframes first-translation { 0% { transform: rotate( 315deg ); } 100% { transform: rotate( 315deg ) translate( 0, -5rem ); } } @keyframes update { 0% { background-color: mediumslateblue; } } @keyframes last-rotation { 0% { transform: rotate( 315deg ) translate( 0, -5rem ); } 100% { transform: rotate( 400deg ) translate( 0, -5rem ); } }
 <head> <style> @import url( "https://fonts.googleapis.com/css?family=Nunito" ); html { overflow: hidden; display: flex; justify-content: center; align-items: center; height: 100%; font-family: "Nunito", sans-serif; } html, body { margin: 0; padding: 0; } .v { display: block; font-size: 2rem; transform: rotate( 180deg ); } p { width: 100%; padding: 0.5rem; position: absolute; bottom: 0; left: 0; } </style> </head> <body> <div id="v-wrp" class="v-wrp"> <b class="v">V</b> </div> <p id="status" class="status"></p> </body>

问题

我需要在 CSS 或 JS 中找到一种方法来重置transform-origin的位置或将其移回变换元素的中心。 在右侧添加更多变换是一种在实时交互环境中对我不起作用的技术。 可以在这里看到一个尝试: Transforms are added...endless

如何计算转换元素的位置并将transform-origin移回其中心,或者如何获取多个转换值并将它们压缩为一个值,使元素保持在同一位置?

您还可以使用topleft来翻译#v-wrp 您可以在transform-origin属性中创建动画。 <b>元素中尝试。 我希望它现在可以正常工作。

您的问题是结构性问题。 保持您的参考点(变换原点)不变,并按层分离您的旋转和平移变换(从原点平移的包含元素和根据需要旋转的内部包含元素)。

从结构上分离这些转换元素将从一开始就防止诸如此类的“跨源”问题。

如果有人还在寻找这样的东西。

@jmcgrory 是对的,有单独的层真的很方便。 但是对于某些情况,以下将起作用。

如果您可以使用 svg,那么 transform-b​​ox 可能会有所帮助。

但是如果你使用任何其他元素而不是它会很困难,因为引用框(可以认为是元素的初始位置)在应用变换后不会改变,并且变换原点将根据其引用框进行处理。 transform-origin 需要与 translate 一起移动,transform:rotate 会变得更复杂,因为您必须计算元素移动的 x 和 y 长度,并基于此需要替换 transform(如果用于任何一个轴)到 x 和 y 并相应地更新变换原点,这种方法非常棘手,但效果很好,并且完全取决于元素运动的数学计算(您不需要编写太多的 css,但必须做一些计算)。

我已经从问题中复制了片段并使其按预期工作。 请检查以下代码以供参考。

 'use strict'; function firstRotation() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.innerHTML = 'First, the V is rotated around it\\'s central axis.\\ The <b>transform-origin</b> is centered.'; v.classList.add( 'first-rotation' ); status.classList.add( 'update' ); }, 1000 ); } function firstTranslation() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.innerHTML = 'Next, the element is translated forward in it\\'s \\ current orientation. The <b>transform-origin</b> stays\\ behind where it was.'; v.classList.remove( 'first-rotation' ); v.classList.add( 'first-translation' ); }, 6000 ); } function info() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.innerHTML = 'This next animation is where it\\'s evident that\\ the <b>transform-origin</b> is no longer centered, but\\ back where it was at the beginning of these transforms'; }, 11000 ); } function lastRotation() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.innerHTML = 'This last rotation is working correctly with calculated transform-origin.' v.classList.remove( 'first-translation' ); v.classList.add( 'last-rotation' ); }, 16000 ); } function end() { var v = document.getElementById( 'v-wrp' ), status = document.getElementById( 'status' ) setTimeout( function() { status.classList.remove( 'update' ); }, 21000 ); } function start() { firstRotation(); firstTranslation(); info(); lastRotation(); end(); } start();
 /* / / / / / / / / / / / / / ANIMATION DEFINITIONS / / / / / / / / / / / / / */ .first-rotation, .first-translation, .update, .last-rotation { animation-duration: 5s; animation-timing-function: ease-in-out; animation-fill-mode: forwards; } .first-rotation { animation-name: first-rotation; } .first-translation { animation-name: first-translation; } .update { animation-name: update; animation-iteration-count: infinite; } .last-rotation { animation-name: last-rotation; } /*/ / / / / / / / / / / / / / ANIMATION KEYFRAMES / / / / / / / / / / / / / /*/ @keyframes first-rotation { 100% { transform: rotate( 315deg ); } } @keyframes first-translation { 0% { transform: rotate( 315deg ); } 100% { transform-origin: calc(-3.536em + 10px) calc(-3.536em + 22px); transform: rotate( 315deg ) translate( -3.536rem, -3.536rem ); } } @keyframes update { 0% { background-color: mediumslateblue; } } @keyframes last-rotation { 0% { transform-origin: calc(-3.536em + 10px) calc(-3.536em + 22px); transform: rotate( 315deg ) translate( -3.536rem, -3.536rem ); } 100% { transform-origin: calc(-3.536em + 10px) calc(-3.536em + 22px); transform: rotate( 400deg ) translate( -3.536rem, -3.536rem ); } }
 <head> <style> @import url( "https://fonts.googleapis.com/css?family=Nunito" ); html { overflow: hidden; display: flex; justify-content: center; align-items: center; height: 100%; font-family: "Nunito", sans-serif; } html, body { margin: 0; padding: 0; } .v { display: block; font-size: 2rem; transform: rotate( 180deg ); } p { width: 100%; padding: 0.5rem; position: absolute; bottom: 0; left: 0; } </style> </head> <body> <div id="v-wrp" class="v-wrp"> <b class="v">V</b> </div> <p id="status" class="status"></p> </body>

您将能够使用 JavaScript 的DOMMatrix或您自己的值来跟踪平移和旋转值。

这是一个非常基本的例子,比如你的小行星游戏: https : //jsfiddle.net/omjktrsh/

矩阵为您提供了操作它的函数,而无需学习所有数学知识。 2D 变体有六个属性,它们是 3x3 矩阵的一部分:

a c e
b d f
0 0 1

在哪里:

  • a = x 轴刻度
  • b = y 轴剪切
  • c = x 轴剪切
  • d = y 轴比例
  • e = x 轴平移
  • f = y 轴平移

您可以使用rotateSelf(deg)使矩阵对其当前值执行旋转,或使用rotate(deg)使矩阵返回具有添加旋转的新矩阵(保留具有相同值的原始矩阵)。

您可以使用translateSelf(x, y)相对于其当前旋转来移动它。 如果你想移动它而不是相对于它的当前旋转,你可以像这样直接操作ef值:

matrix.e += x; // x axis translation amount
matrix.f += y; // y axis translation amount

您可以轻松地应用任意数量的旋转,而无需在 CSS 中堆叠它们,然后使用toString()以 CSS 形式输出矩阵:

const matrix = new DOMMatrix();
const el = document.getElementById("transform-me");
// manipulate matrix as much as you want
...
matrix.translateSelf(...);
...
matrix.rotateSelf(...);
...
// apply matrix to elements css -> matrix(a, b, c, d, e, f)
el.style.transform = matrix.toString();

缺点是 DOMMatrix 的浏览器支持较少: https ://caniuse.com/dommatrix

如果您想支持不支持 DOMMatrix 的浏览器,您仍然可以在这些浏览器中使用自己的数学和transform: matrix(a, b, c, d, e, f)语法: https : //caniuse.com /transforms2d

如果您想了解 2d 变换矩阵背后的数学原理,请参阅Wikipedia上的示例。 请注意,某些资源使用翻转矩阵到上面的矩阵:

a b 0
c d 0
e f 1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM