들어가며: 왜 rotateZ()를 따로 배워야 할까?
CSS에서 요소를 회전시키는 방법은 여러 가지가 있습니다. 가장 흔히 쓰는 rotate() 함수도 있고, 3D 변환을 위한 rotateX(), rotateY(), rotateZ()도 있죠. 그런데 rotate()와 rotateZ()는 화면상으로 똑같이 보입니다. 둘 다 요소를 시계/반시계 방향으로 돌리니까요.
그럼 왜 CSS 스펙에 두 개가 공존할까요? 🤔
실무에서 이 둘을 구분해서 써야 하는 상황이 분명히 있습니다. 특히:
- 3D 변환과 함께 쓸 때 (예: 아이소메트릭 카드, 큐브 애니메이션)
- GPU 가속을 활용해 부드러운 애니메이션을 만들 때
- 브라우저의 레이아웃 계산 부하를 줄이고 싶을 때
이 글에서는 rotateZ()의 문법, 2D rotate()와의 차이, 그리고 실전에서 바로 써먹을 수 있는 예제를 다룹니다.

rotateZ() 기본 문법과 단위
rotateZ() 함수는 하나의 인자(각도)만 받습니다. 각도는 양수면 시계 방향, 음수면 반시계 방향으로 회전합니다.
/* 각도 단위별 사용 예 */
.element {
/* 도(deg) - 가장 일반적 */
transform: rotateZ(90deg); /* 시계 방향 90도 */
transform: rotateZ(-180deg); /* 반시계 방향 180도 */
/* 회전수(turn) - 직관적 */
transform: rotateZ(0.25turn); /* 1/4 바퀴 = 90도 */
transform: rotateZ(1turn); /* 한 바퀴 = 360도 */
/* 라디안(rad) - 수학/애니메이션에 유용 */
transform: rotateZ(1.57rad); /* 약 90도 */
transform: rotateZ(6.28rad); /* 한 바퀴 */
/* 그래디언(grad) - 덜 쓰임 */
transform: rotateZ(100grad); /* 90도 */
}
팁: 실무에서는
deg나turn을 가장 많이 씁니다.turn은 애니메이션 키프레임에서 '한 바퀴, 두 바퀴' 같은 표현을 할 때 직관적이에요.

rotate() vs rotateZ(): 언제 무엇을 써야 할까?
시각적 차이는 없다? — 맞다, 하지만 내부는 다르다
두 함수의 시각적 결과는 동일합니다. 하지만 브라우저가 처리하는 방식이 달라요.
| 특징 | rotate() | rotateZ() |
|---|---|---|
| 변환 행렬 | 2D 행렬 (3x3) | 3D 행렬 (4x4) |
| GPU 가속 | ❌ (메인 스레드) | ✅ (합성 레이어) |
| 3D 변환과 결합 | ⚠️ 비권장 (계산 오류 가능) | ✅ 권장 |
| 성능 (복잡한 DOM) | 보통 | 더 부드러움 |
실전 예제 1: GPU 가속을 활용한 부드러운 로딩 스피너
/* ❌ 2D rotate 사용 - DOM이 복잡하면 버벅일 수 있음 */
.spinner-bad {
animation: spin-bad 1s linear infinite;
}
@keyframes spin-bad {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* ✅ rotateZ 사용 - GPU 레이어로 승격되어 부드러움 */
.spinner-good {
animation: spin-good 1s linear infinite;
}
@keyframes spin-good {
from { transform: rotateZ(0deg); }
to { transform: rotateZ(360deg); }
}
주의:
rotateZ()를 쓰면 브라우저가 해당 요소를 별도의 GPU 합성 레이어로 승격시킵니다. 단, 너무 많은 요소에 남발하면 오히려 GPU 메모리가 부족해질 수 있으니 꼭 필요한 곳(애니메이션 대상, 스크롤 시 고정되는 요소 등)에만 사용하세요.
실전 예제 2: 아이소메트릭 카드 (3D 변환과 결합)
/* 3D 효과를 위한 부모 컨테이너 */
.isometric-container {
perspective: 1000px; /* 원근감: 값이 작을수록 더 극적인 3D 효과 */
}
/* 카드 본체: X축 60도 기울이고 Z축으로 -45도 회전 */
.isometric-card {
transition: transform 0.5s ease;
transform: rotateX(60deg) rotateZ(-45deg);
/* ⚠️ rotate(-45deg)를 쓰면 3D 행렬 계산이 꼬일 수 있음 */
}
/* 호버 시 정면으로 돌아오기 */
.isometric-card:hover {
transform: rotateX(0deg) rotateZ(0deg) scale(1.1);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
핵심: 3D 변환(
rotateX,rotateY)과 함께 쓸 때는 반드시rotateZ()를 사용하세요.rotate()는 2D 행렬로 매핑되기 때문에, 3D 함수들과 섞이면 브라우저가 행렬 수학을 잘못 계산할 수 있습니다.
실전 예제 3: 동전 튀기기 애니메이션 (3축 회전)
.stage {
perspective: 800px;
}
.tumbling-coin {
animation: tumble 3s infinite linear;
}
@keyframes tumble {
0% {
transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);
}
100% {
transform: rotateX(360deg) rotateY(180deg) rotateZ(360deg);
}
}
이 예제에서 rotateZ()는 동전이 테이블 위에서 빙글빙글 도는 효과를 만듭니다. rotate()로는 이렇게 3축을 동시에 제어할 수 없어요.

정리 및 실무 적용 팁
언제 rotateZ()를 써야 할까?
- 3D 변환과 함께 사용할 때 —
rotateX(),rotateY()와 조합한다면 무조건rotateZ() - 성능이 중요한 애니메이션 — 로딩 스피너, 무한 회전, 스크롤 기반 효과 등
- GPU 합성 레이어가 필요할 때 — 복잡한 DOM 트리에서 특정 요소만 부드럽게 움직이고 싶다면
주의사항
- 모든 회전에
rotateZ()를 쓰는 것은 오버엔지니어링입니다. 단순한 2D 회전(예: 아이콘 돌리기)은rotate()로 충분해요. rotateZ()를 과도하게 사용하면 GPU 메모리 사용량이 늘어날 수 있습니다. 모바일 기기에서는 특히 주의하세요.transform-style: preserve-3d와 함께 쓸 때 자식 요소의 3D 공간이 유지되는지 꼭 확인하세요.
다음 단계 학습 방향
perspective와perspective-origin의 관계 이해하기transform-style: preserve-3d로 3D 공간 유지하기will-change: transform을 활용한 추가 성능 최적화
근거자료: 이 글은 CSS-Tricks의 rotateZ() 알마낙 문서를 기반으로 실무 경험을 더해 재구성했습니다.