본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Frontend

transform: 이동·회전·확대·기울이기

작성 2026. 10. 13.추가
목차10개 항목
출처와 참고

riverkim.kr에 쓴 글을 다시 정리하고, 3D 변형은 web.dev 「Learn CSS」 강좌의 Functions 모듈로 보강한 노트다. 「translate와 위치 지정(top·left) 고르기」는 Front End Interview Handbook의 「CSS 질문」을 바탕으로 보강했다.

transform이란

transform은 요소에 이동(translate), 확대·축소(scale), 회전(rotate), 기울이기(skew) 를 적용하는 속성이다. 요소가 차지하는 원래 자리는 그대로 두고 그려지는 모습만 바꾸므로 주변 요소의 배치에 영향을 주지 않는다. transition이나 animation과 함께 쓰면 움직임이 되고, 단독으로 쓰면 바로 적용된 상태로 렌더링된다.

transform 함수

함수설명값
translate(x, y)X축으로 x, Y축으로 y만큼 이동px, %, em 등
translateX(n) / translateY(n)한 축으로만 이동px, %, em 등
scale(x, y)X축 x배, Y축 y배 확대·축소0과 양수
scaleX(n) / scaleY(n)한 축으로만 확대·축소0과 양수
rotate(angle)angle만큼 회전±deg
skew(x-angle, y-angle)X축·Y축으로 기울임±deg
skewX(angle) / skewY(angle)한 축으로만 기울임±deg

여러 함수를 공백으로 이어 쓸 수 있고, 적힌 순서대로 적용된다.

.card:hover {
  transform: translateY(-4px) scale(1.02);
}

translate의 %는 부모가 아니라 요소 자기 크기 기준이다. 아래 가운데 정렬이 동작하는 이유다.

개별 변형 속성

translate, rotate, scale은 transform 함수일 뿐 아니라 독립된 CSS 속성이기도 하다. 모든 주요 브라우저가 2022년부터 지원한다.

.card { translate: 0 0; scale: 1; transition: translate .2s, scale .2s; }
.card:hover { translate: 0 -4px; }        /* scale은 그대로 둔 채 이동만 바꾼다 */
.card:active { scale: .98; }

transform 한 줄에 함수를 몰아 쓰면 호버에서 이동만 바꾸려 해도 확대 값까지 다시 적어야 한다. 개별 속성은 서로 덮어쓰지 않아 상태별로 따로 바꾸기 쉽다. 적용 순서는 작성 순서와 상관없이 항상 translate → rotate → scale → transform이다.

3D 변형과 원근

함수·속성하는 일
rotateX(), rotateY(), rotateZ()한 축을 중심으로 회전. rotate()는 rotateZ()와 같다
rotate3d(x, y, z, 각도)벡터 (x, y, z)를 축으로 회전
translateZ(), translate3d()화면 앞뒤(Z축)로 이동
scaleZ(), scale3d()Z축 배율
perspective 속성 / perspective() 함수보는 사람과 Z=0 평면 사이의 거리. 작을수록 원근이 강하다. 속성은 자식에, 함수는 그 요소에 적용된다
perspective-origin소실점 위치
transform-style: preserve-3d자식도 같은 3D 공간에 놓는다(카드 뒤집기)
backface-visibility: hidden뒤집혔을 때 뒷면을 숨긴다
.scene { perspective: 800px; }
.card  { transform-style: preserve-3d; transition: rotate .6s; }
.card.flipped { rotate: y 180deg; }
.card :is(.front, .back) { backface-visibility: hidden; }
.card .back { rotate: y 180deg; }   /* 앞뒤 면을 같은 칸에 겹쳐 둔다 */

transform·opacity만 바꾸면 합성만 다시 돌아 부드럽다(변경이 다시 도는 단계). transform이 있는 요소는 새 쌓임 맥락을 만들고, 그 안의 position: fixed 자식의 기준이 된다(CSS position과 z-index).

translate와 위치 지정(top·left) 고르기

요소를 옮기는 방법은 두 가지다. 기준이 다르다. 움직임이면 translate, 놓을 자리면 위치 지정이다.

translate()·translate 속성position: absolute + top·left
다시 도는 렌더링 단계합성만. 브라우저가 요소를 별도 합성 레이어에 올려 GPU로 처리하기도 한다값이 바뀔 때마다 레이아웃(리플로)부터 다시 한다
원래 자리그대로 차지한다(position: relative로 옮긴 것과 비슷하다)흐름에서 빠져 자리를 비운다
% 기준요소 자기 크기컨테이닝 블록 크기
어울리는 곳애니메이션·드래그·스크롤 연동처럼 매 프레임 바뀌는 이동배지·드롭다운·오버레이처럼 레이아웃상 자리를 정하는 배치
.toast { position: fixed; inset-block-end: 1rem; inset-inline-end: 1rem; }  /* 자리는 위치 지정으로 */
.toast[data-state="enter"] { animation: slide-in .2s ease-out; }
@keyframes slide-in { from { translate: 0 120%; } }                           /* 움직임은 translate로 */

애니메이션에서 top·left를 바꾸면 매 프레임 레이아웃을 다시 계산해 버벅이기 쉽다. 반대로 translate로 옮긴 요소는 원래 자리를 계속 차지하므로, 레이아웃에서 실제로 자리를 옮겨야 하면 위치 지정이나 플렉스·그리드 배치를 쓴다.

가운데 정렬 패턴

증상

팝업을 화면 가운데 두려고 top: 50%; left: 50%만 주면 몇십 픽셀 어긋난다. 위치가 요소의 왼쪽 위 모서리 기준으로 계산되기 때문이다. 모서리가 화면 중앙에 오고, 요소는 오른쪽 아래로 치우친다.

해결

자기 너비·높이의 절반만큼 되돌린다.

.pop-up {
  position: fixed;   /* 뷰포트 기준 */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 999;
}
top/left 50%만        translate(-50%, -50%) 추가
┌──────────────┐      ┌──────────────┐
│              │      │              │
│       ┌───┐  │      │     ┌───┐    │
│       │   │  │      │     │ ● │    │
│       └───┘  │      │     └───┘    │
└──────────────┘      └──────────────┘
 모서리가 중앙          요소의 중심이 중앙

요소 크기를 몰라도 동작한다는 점이 장점이다. 부모 안에서 가운데 두려면 position: absolute와 부모의 position: relative를 쓴다(position).

지금은 변형 없이 가운데 정렬하는 방법이 더 간단하다.

상황방법
일반 레이아웃 안부모에 display: grid; place-items: center 또는 Flexbox(justify-content·align-items: center)
고정·절대 위치 팝업position: fixed; inset: 0; margin: auto; width: fit-content; height: fit-content
모달 대화 상자<dialog>의 showModal(). 브라우저가 화면 가운데·최상위 레이어에 띄운다

정리

  • transform은 자리는 그대로, 보이는 모습만 바꾼다.
  • translate의 %는 자기 크기 기준이다.
  • 움직임은 합성만 다시 도는 translate로, 레이아웃상 자리는 위치 지정으로 정한다.
  • 크기를 모르는 팝업의 정중앙 배치: top·left: 50% + translate(-50%, -50%). 그리드 place-items: center, inset: 0; margin: auto, <dialog>도 같은 일을 한다.
  • 상태마다 따로 바꿀 값은 translate·rotate·scale 개별 속성으로 쓴다.

참고 자료

관련 노트: position, Float와 Flexbox, CSS 애니메이션: transition과 @keyframes, CSS 함수: calc()·clamp()와 수학 함수

원본 기록4

댓글

GitHub 계정으로 댓글을 남길 수 있어요.