1

I went through CSS spec, MDN/Opera articles on transform-origin, , but couldn't understand exactly how transform-origin works.

I have setup a jsfiddle. The div with class "test" is a "50px" wide square. There is a button clicking on which rotates the div 30 degrees. Sample HTML is as below

<div class='container'>
    <div class='test'></div>
</div>
<button class='button'>
    Rotate
</button>

Sample CSS is as below

.rotate {
  transform: rotate(30deg);
  transform-origin: 70px 80px;
}

If I set transform origin to the edges of the square like (0,0)/(50px,0)/(0,50px)/(50px, 50px) or any point on the circumference/area inside the square I can slightly visualize how the transform origin is working. But if I set the property to a point outside the bounds of the square, I couldn't visualize or understand where exactly the div is shifted to.

In MDN/Opera article, there is a phrase as below,

From MDN

"This property is applied by first translating the element by the negated value of the property, then applying the element's transform, then translating by the property value.)"

From Opera

Technically the transform origin is applied by calculating the negation of the transform-origin value (-3em on the X axis, and the top of the element in the example above), translating the element to this value, then applying the transform that is specified in the transform property, then translating the element by the actual value of the transform-origin.

It adds to further confusion if I try to follow the above steps and trace where exactly the div will be placed in the co-ordinate system.

Any help will be highly appreciated, Thanks

Community
  • 1
  • 1
  • 1
    Have a look at the values section: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin - it pretty much explains it - your above origin is 70px on the x axis from the left edge of your original shape and 80px from the top edge of your original shape – Pete Mar 22 '19 at 15:00
  • Also a good article: https://css-tricks.com/almanac/properties/t/transform-origin/ – Pete Mar 22 '19 at 15:06

1 Answers1

0

Here is a very good pen by Dan Wilson that will give you a visual explanation of how Transform Origin works:

https://codepen.io/danwilson/full/EXqEZM

var display = document.getElementById('transform-origin');
var origin = document.querySelector('.origin');
var style = document.documentElement.style;

var autopilot;
autopilot = setTimeout(() => {
  change();
  autopilot = setInterval(change, 3000)
}, 1500);

function change(ex, ey) {
  var x = ex || (Math.random());
  var y = ey || (Math.random());
  style.setProperty('--x', x);
  style.setProperty('--y', y);
  display.textContent = Math.round(x * 100) + '% ' + Math.round(y * 100) + '%';
}

document.documentElement.addEventListener('mouseup', onPress);
document.documentElement.addEventListener('touchend', onPress);
var width = window.innerWidth;
var height = window.innerHeight;
var box = origin.getBoundingClientRect();
var side = box.right - box.left;

function onPress(e) {
  clearTimeout(autopilot);
  clearInterval(autopilot);
  
  var x = e.clientX || e.changedTouches[0].clientX;
  var y = e.clientY || e.changedTouches[0].clientY;
  
  if (window.innerWidth !== width || window.innerHeight !== height) {
    box = origin.getBoundingClientRect();
    width = window.innerWidth;
    height = window.innerHeight;
    side = box.right - box.left;
  }
  
  var ex = (x - box.left) / side;
  var ey = (y - box.top) / side;
  
  change(ex,ey);
}
:root {
  --x: .5;
  --y: .5;
  --side: 30vmin;
  --duration: 1500ms;
  --easing: ease-in-out;
}

.shape {
  animation: rotate 1000ms infinite linear;
  transition: transform-origin var(--duration) var(--easing);
  transform-origin: calc(var(--x) * 100%) calc(var(--y) * 100%);
  
  
  width: var(--side);
  height: var(--side);
  background: 
    linear-gradient(315deg, hsl(248, 40%,50%) 10%, transparent 10%, transparent), 
    linear-gradient(225deg, hsl(348, 40%,50%) 10%, transparent 10%, transparent), 
    linear-gradient(135deg, hsl(48, 40%,50%) 10%, transparent 10%, transparent), 
    linear-gradient(45deg, hsl(168, 40%,50%) 10%, hsl(168, 70%,50%) 10%, hsl(168, 70%,50%));
  position: relative;
  will-change: transform, transform-origin;
}
.point {
  --point: 1vmin;
  background: black;
  width: var(--point);
  height: var(--point);
  border-radius: 50%;
  position: absolute;
  top: calc(var(--point) * -.5);
  left: calc(var(--point) * -.5);
  transform: translate(calc(var(--x) * var(--side)), calc(var(--y) * var(--side)));
  transition: transform var(--duration) var(--easing);
  will-change: transform;
  opacity: .6;
}
.origin {
  width: var(--side);
  height: var(--side);
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 1px dashed hsl(233, 70%, 50%);
  background: linear-gradient(315deg, hsla(248, 40%,50%, .2) 10%, transparent 10%, transparent), 
    linear-gradient(225deg, hsla(348, 40%,50%, .2) 10%, transparent 10%, transparent), 
    linear-gradient(135deg, hsla(48, 40%,50%, .2) 10%, transparent 10%, transparent), 
    linear-gradient(45deg, hsla(168, 40%,50%, .2) 10%, transparent 10%, transparent);
}

@keyframes rotate {
  100% {
    transform: rotate(360deg)
  }
}





p {
  position: absolute;
  top:50%;
  left:50%;
  transform: translate(-50%,var(--side));
  text-align: center;
  z-index:10;
}
span {
  display: block;
}
#instruction {
  position: absolute;
  top: 2vmin;
  left: 50%;
  transform: translateX(-50%);
  opacity: .78;
  text-align: center;
}

body {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  background: radial-gradient(circle, hsl(198, 70%, 96%), hsl(198, 70%, 90%));
  font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
}
*, *::before, *::after {
  box-sizing: border-box;
}
<!--
Scale: qXPdbw
Skew: PKJqJW
-->
<div class="shape"></div>
<div class="origin">
  <div class="point"></div>
</div>
<p>transform-origin:<span id="transform-origin">50% 50%</span></p>

<span id="instruction">Press Anywhere to&nbsp;Change</span>
MarioD
  • 1,703
  • 1
  • 14
  • 24