CSS perspective 3D 카드 만들기

CSS만으로 카드나 박스를 입체적으로 회전시키려면 perspective, rotateX, rotateY, rotateZ, translateZ, scale 여섯 개 값이 어떤 순서로 합쳐지고 각각 무엇을 바꾸는지부터 알아야 합니다.
이 여섯 값은 감으로 맞추는 게 아니라 정해진 규칙대로 계산되는 값이라, 규칙을 알면 결과를 그대로 예측할 수 있습니다.
프론트엔드 개발자나 퍼블리셔가 호버 카드나 3D 큐브 효과를 만들 때, 값을 하나씩 바꿔가며 이 규칙을 직접 확인할 수 있도록 정리했습니다.
요약 ① perspective는 회전시킬 요소가 아니라 그 부모에 걸어야 원근 왜곡이 생깁니다. ② transform 함수는 왼쪽부터 순서대로 계산되어, 같은 값이라도 순서를 바꾸면 결과가 달라집니다. ③ translateZ는 perspective 값에 따라 크기가 달리 보이지만, scale은 원근과 무관하게 화면 크기를 그대로 곱합니다.
CSS 3D 카드가 자꾸 평면처럼 보이는 이유
검색해서 찾은 CSS 3D 카드 예제를 그대로 붙여 넣었는데, 카드가 입체적으로 돌지 않고 그냥 비스듬히 눌린 사각형처럼만 보이는 경우가 있습니다. rotateY(30deg)를 분명히 줬는데도 원근감 없이 평면이 기울어진 모양만 나오는 것입니다.
원인은 대부분 두 가지 중 하나입니다. perspective를 아예 선언하지 않았거나, 회전시키려는 요소 자신에게 perspective를 걸어버린 경우입니다.
perspective는 시점(뷰어)과 z=0 평면 사이의 가상 거리를 정의하는 값인데, 이 거리가 적용되는 대상은 그 속성을 가진 요소의 자식들이지 요소 자신이 아닙니다. 그래서 회전할 요소 본인에게 걸면 효과가 나타나지 않습니다.
또 다른 원인은 transform 함수의 순서입니다. rotateY(30deg) translateZ(50px)와 translateZ(50px) rotateY(30deg)는 숫자가 같아도 결과가 다릅니다. CSS는 transform에 나열된 함수를 왼쪽부터 순서대로 적용하기 때문입니다.
perspective·rotate·translateZ·scale이 합쳐지는 순서
아래 순서를 그대로 따라 하면 도구 없이도 같은 결과를 CSS로 직접 만들 수 있습니다.
- perspective는 부모 요소에 선언합니다. 회전시킬 카드를 감싸는 컨테이너에
perspective: 600px;를 겁니다. 이 값은 시점에서 z=0 평면까지의 가상 거리이며, 카드 자신이 아니라 카드를 담은 부모에 걸어야 카드가 돌 때 원근 왜곡이 생깁니다. - perspective 값의 크기가 왜곡의 정도를 정합니다. 값이 작을수록(예: 200
400px) 시점이 카드에 바짝 붙은 셈이 되어 회전 시 앞뒤 면의 크기 차이가 크게 벌어져 왜곡이 강해집니다. 값이 클수록(예: 15002000px) 시점이 멀어진 셈이 되어 왜곡이 완만해지고 평면 회전에 가까워집니다. - rotateX·rotateY·rotateZ는 서로 다른 축을 돕니다. rotateX는 수평(가로) 축을 기준으로 돌아 카드의 위아래가 앞뒤로 기울고, rotateY는 수직(세로) 축을 기준으로 돌아 카드의 좌우가 앞뒤로 기울며, rotateZ는 화면을 정면으로 바라보는 축을 기준으로 돌아 2D 회전과 같은 모양이 됩니다.
- translateZ는 카드를 시점 쪽으로 당기거나 밀어냅니다. 양수 값은 카드를 시점 가까이(화면 앞으로), 음수 값은 시점에서 멀리(화면 뒤로) 이동시킵니다. perspective가 적용된 상태에서는 이 이동만으로도 카드가 커지거나 작아 보입니다. 가까워지면 크게, 멀어지면 작게 보이는 원근 투영 때문입니다.
- scale은 원근과 무관하게 화면상의 크기만 곱합니다. translateZ가 '거리를 옮겨서 결과적으로 크기가 달라 보이게' 하는 것과 달리, scale은 z축 이동 없이 요소의 렌더링 크기 자체를 지정한 배율만큼 곱합니다. translateZ(100px)와 scale(1.5)가 둘 다 카드를 커 보이게 만들 수는 있어도, 원근 왜곡에 반응하는지 여부가 다릅니다.
- 최종 transform 문자열은 순서대로 이어 붙입니다.
transform: rotateX(25deg) rotateY(-30deg) rotateZ(0deg) translateZ(0px) scale(1);형태로, 각 함수가 왼쪽부터 순서대로 계산되어 최종 모양이 결정됩니다. 여기에transform-style: preserve-3d;와transition: transform 0.1s ease;를 더하면 값이 바뀔 때 부드럽게 전환되는 카드가 완성됩니다.
여섯 값을 손으로 하나씩 바꿔가며 브라우저에서 새로고침하는 방식으로도 이 규칙을 확인할 수 있습니다. 다만 값을 바꿀 때마다 코드를 고치고 저장하고 새로고침하는 과정을 반복해야 해서, 여러 조합을 눈으로 비교하기까지 시간이 걸립니다.
저희 도구로 확인하기.
슬라이더로 값을 조절하면 CSS 코드가 실시간으로 갱신되며, 모든 계산은 브라우저에서만 처리되어 서버로 전송되는 데이터가 없습니다.

자주 헷갈리는 부분 정리
값 자체는 어렵지 않지만, 아래 네 가지 지점에서 결과가 예상과 달라지는 경우가 많습니다.
| 실수 | 나타나는 증상 | 원인 |
|---|---|---|
| perspective를 회전시킬 요소 자신에게 건다 | 회전은 되는데 원근 왜곡 없이 평평해 보인다 | perspective는 그 속성을 가진 요소의 자식에게 적용되는 값이라 자신에게는 효과가 없다 |
| perspective 자체를 빠뜨린다 | rotateX/rotateY를 줘도 기울어진 평면처럼만 보인다 | 원근 투영이 없으면 회전해도 앞뒤 면의 크기 차이가 생기지 않는다 |
| transform 함수 순서를 바꾼다 | 같은 숫자를 넣었는데 예제와 모양이 다르게 나온다 | transform 함수는 왼쪽부터 순서대로 적용되어 순서가 곧 계산 순서다 |
| 큐브처럼 중첩된 3D 요소에 preserve-3d를 빠뜨린다 | 각 면이 입체로 안 보이고 하나로 겹쳐 보인다 | 기본값 flat은 자식의 3D 변환을 부모 평면 위로 눌러버린다 |
transform-style: preserve-3d가 필요한 이유도 같은 원리입니다. 기본값 flat 상태에서는 자식 요소들의 3D 변환이 부모가 놓인 평면 위로 눌려서 렌더링됩니다.
여러 개의 면을 조합해 큐브처럼 보이게 하려면, 그 면들을 감싸는 요소에 preserve-3d를 지정해 자식들의 3D 위치가 눌리지 않고 그대로 유지되게 해야 합니다.
정리
- perspective는 회전할 요소가 아니라 부모에 걸어야 하고, 값이 작을수록 원근 왜곡이 커집니다.
- rotateX·rotateY·rotateZ는 서로 다른 축을 돌고, transform 함수는 왼쪽부터 순서대로 계산됩니다.
- translateZ는 perspective에 반응해 크기가 달라 보이고, scale은 원근과 무관하게 화면 크기만 곱합니다.
- 중첩된 3D 요소(큐브 등)는
transform-style: preserve-3d가 있어야 눌리지 않고 입체로 유지됩니다. - 슬라이더로 값을 바꿔보면 이 규칙이 실시간 CSS 텍스트로 그대로 확인됩니다.
슬라이더로 값을 조절하면 CSS 코드가 실시간으로 갱신되며, 모든 계산은 브라우저에서만 처리되어 서버로 전송되는 데이터가 없습니다.
자주 묻는 질문
perspective 값은 몇 px이 적당한가요?
정해진 정답은 없습니다. 같은 회전 각도라도 perspective가 작을수록(200~400px) 왜곡이 강조되고, 클수록(1000px 이상) 왜곡이 옅어지는 관계만 정해져 있습니다. 원하는 왜곡의 정도는 상황마다 다르므로, 슬라이더로 여러 값을 직접 비교해보고 고르는 방법이 있습니다.
rotateX와 rotateY의 순서를 바꾸면 결과가 달라지나요?
네, 달라집니다. transform 함수는 왼쪽부터 순서대로 계산되므로 rotateX(25deg) rotateY(-30deg)와 rotateY(-30deg) rotateX(25deg)는 서로 다른 결과를 만듭니다. 두 회전이 서로 다른 축을 돌기 때문에 순서를 바꾸면 최종 방향이 달라집니다.
translateZ만 바꿔도 카드가 커 보이는데 scale과 뭐가 다른가요?
translateZ는 카드를 시점 쪽으로 물리적으로 이동시키고, perspective 값에 따라 그 결과로 크기가 달라 보이게 됩니다. scale은 이동 없이 렌더링 크기 자체를 배율만큼 곱하는 것이라 perspective 값과 무관하게 항상 같은 비율로 커지거나 작아집니다.
3D 카드와 3D 큐브 탭은 뭐가 다른가요?
3D 카드 탭은 하나의 그라디언트 카드에 perspective와 회전·이동·비율 값을 적용해 단일 평면이 입체적으로 기울어지는 모습을 보여줍니다. 3D 큐브 탭은 앞/뒤/좌/우/위/아래 여섯 면을 translateZ(50px)와 rotateY/rotateX로 배치해 정육면체 형태를 만들고, 같은 슬라이더 값을 여섯 면 전체에 반영해 함께 회전시킵니다.
