Reduce multiple CSS transformations into fewer one

2019-08-01 03:13发布

问题:

I have an element with a ton of CSS transformations like this:

transform:  translateX( 0 )
            translateY( -1rem )
            rotate( 45deg ) 
            translateY( -2.5rem )
            rotate( 45deg )
            translateY( 5rem );

The order of these properties matter as they affect how the element ends up being positioned on the page. I've done some tinkering and came up with the same exact end result with fewer properties:

transform:  rotate( 90deg ) translateX( -2.8rem ) translateY( 3.25rem );

You can test this by commenting and uncommenting out the comment in the snippet below to see nothing changes ( the transformations equal the same result ).

I did this manually and it took some time to find the exact transformations that would get me the same result. I'm trying to do this for literally thousands of properties in real time...

Is there a formula? Is there a CSS hack? Is there a simple way of doing this - I don't know where to start. O.o

html {
  display: flex;
  height: 100%; 
  justify-content: center;
  align-items: center;
}

div {
  padding: 2.5rem 1rem;
  background-color: #4cc;
  color: #eee;
  text-align: center;
  border: 1px solid #eee;
  border-radius: 0.25rem;
  
  transform:  translateX( 0 )
              translateY( -1rem )
              rotate( 45deg ) 
              translateY( -2.5rem )
              rotate( 45deg )
              translateY( 5rem );
  
/*transform:  rotate( 90deg ) translateX( -2.8rem ) translateY( 3.25rem );*/
}
<div>
  transformed<br>element
</div>

Edit: You might be wondering: Why do this!? Well here is a problem I had earlier: Move transform-origin back to the center of the element in CSS. I solved it like this: Transforms are added...endlessly . But now I have endless transforms and this is why I ask.

I have tons of dynamic transforms that look like this:

回答1:

I don't know of any other way, but came up with this "hacky" method based on keyframes

UPDATE: Removed jQuery

var currentAngle = 0,
  styleElment = document.createElement('style'), // create a style element to insert dynamic keyframes
  styleSheet,
  animState = 0; // toggle between 2 animation states

document.head.appendChild(styleElment);
styleSheet = styleElment.sheet;

// insert 2 default keyframes to the created stylesheet
styleSheet.insertRule("@keyframes rotate_1 {0% {transform: rotate(0deg);} 100% {transform: rotate(0deg)}}"); // at index 1
styleSheet.insertRule("@keyframes rotate_2 {0% {transform: rotate(0deg);} 100% {transform: rotate(0deg)}}"); // at index 0

document.getElementById("rotateBtn").onclick = function() {
  var newAngle = currentAngle + 30,
    transformCSS = "rotate(" + newAngle + "deg)",
    keyframe_1 = "transform: rotate(" + currentAngle + "deg);",
    keyframe_2 = "transform: rotate(" + newAngle + "deg);",
    animationCSS;

  styleSheet.cssRules[animState][0].style.cssText = keyframe_1; // sets value at 0%
  styleSheet.cssRules[animState][1].style.cssText = keyframe_2; // sets value at 100%

  if (animState === 0) {
    animState = 1;
    animationCSS = "rotate_2 1s";
  } else {
    animState = 0;
    animationCSS = "rotate_1 1s";
  }

  document.getElementById("container").style.animation = animationCSS;
  document.getElementById("container").style.transform = transformCSS;

  currentAngle = newAngle;
};
#container {
  width: 50px;
  height: 50px;
  background: red;
}
<div id="container"></div>
<button id="rotateBtn">Rotate</button>