변환 순서와 transform-origin
이번에는 transform에서 사람을 제일 많이 헷갈리게 만드는 두 가지를 봅니다.
순서와 기준점입니다.
같은 translate, rotate, scale을 써도 순서가 바뀌면 결과가 달라집니다. 그리고 같은 회전을 해도 어디를 기준으로 돌리느냐에 따라 화면 위치가 달라집니다. transform은 숫자만 맞다고 끝나는 세계가 아닙니다. 순서와 origin까지 같이 봐야 합니다.
행렬 곱은 순서를 탄다
숫자 곱셈은 보통 순서를 바꿔도 같습니다.
2 * 3 = 3 * 2
하지만 행렬 곱은 그렇지 않습니다.
A * B != B * A
그래서 translate 후 rotate와 rotate 후 translate는 다른 결과를 만듭니다. 하나는 이동한 다음 돌고, 다른 하나는 돌아간 좌표계에서 이동합니다. 말장난 같지만 화면에서는 확실히 다르게 보입니다.
CSS transform 목록도 최종 matrix를 만들 때 순서가 결과에 영향을 줍니다. 편집기에서는 이 순서를 테스트로 고정해두는 것이 좋습니다. “아마 이 순서겠지”는 나중에 꼭 발목을 잡습니다.
transform-origin은 몰래 들어가는 변환이다
CSS의 transform-origin은 회전과 스케일의 기준점을 정합니다. 예를 들어 center 기준 회전은 그냥 R 하나가 아니라, origin으로 옮겼다가 회전하고 다시 되돌리는 과정입니다.
M = T(origin) * R * S * T(-origin)
이렇게 보면 origin이 왜 중요한지 보입니다. 기준점이 바뀌면 같은 각도, 같은 scale이어도 최종 위치가 달라집니다.
Figma와 CSS는 기본 기준점이 다르다
여기서 Figma export를 만들 때 자주 나오는 차이가 있습니다.
Figma rotation 기준점 = object의 local top-left
CSS transform 기본 기준점 = element의 center
Figma plugin API의 rotation은 node의 top-left 기준으로 해석됩니다. 반면 CSS는 아무 설정을 하지 않으면 transform-origin: 50% 50%입니다. 그래서 Figma의 relativeTransform을 CSS matrix(...)로 그대로 옮길 때는 보통 origin을 명시합니다.
.figma-node {
position: absolute;
width: 120px;
height: 80px;
transform-origin: 0 0;
transform: matrix(a, b, c, d, e, f);
}
transform-origin: 0 0은 “이 matrix는 local top-left를 기준으로 계산된 값입니다”라고 브라우저에게 알려주는 안전핀입니다. 이걸 빼먹으면 matrix 숫자는 맞는데 화면 위치가 살짝 틀어집니다. 숫자가 맞는데 틀리는 버그, 아주 얄밉죠.
반대로 center 기준 회전을 직접 만들고 싶다면 origin 속성에 기대지 말고 translation을 다시 계산할 수 있습니다.
pivotLocal = (width / 2, height / 2)
pivotParent = oldMatrix * pivotLocal
newTranslation =
pivotParent - newLinearPart * pivotLocal
임의의 pivot도 똑같습니다.
pivotLocal = (px, py)
pivotParent = oldMatrix * pivotLocal
newE = pivotParent.x - (a * px + c * py)
newF = pivotParent.y - (b * px + d * py)
즉 transform-origin은 “각도를 바꾸는 속성”이 아니라, pivot이 움직이지 않도록 translation을 보정하는 문제로 볼 수 있습니다.
에디터는 origin 정책을 정해야 한다
CSS의 기본 transform-origin은 center입니다. 하지만 에디터 내부 수학 모델은 top-left 기준으로 계산하는 경우가 많습니다. 둘을 맞추지 않으면 핸들 계산과 실제 화면이 어긋납니다.
가능한 정책은 이런 식입니다.
- 항상 top-left 기준
- 항상 center 기준
- 사용자가 바꿀 수 있는 custom pivot
중요한 건 하나를 고르고 명시하는 것입니다. CSS 기본값에 조용히 맡겨두면, 나중에 rotation handle이 엉뚱한 곳을 기준으로 돌아갑니다.
데모에서 볼 것
데모에서는 rotate 후 translate와 translate 후 rotate를 비교하고 matrix readout을 확인합니다.
오늘의 핵심은 transform이 “무엇을 하느냐”만큼 “언제 하느냐”와 “어디를 기준으로 하느냐”가 중요하다는 점입니다. 순서와 origin을 잡으면 transform이 한결 얌전해집니다.