친절한효자손 취미생활

지난 시간에 소개해드렸던 3D 카드 방법을 응용해서 이번에는 입체형 오브젝트로 만들어 보았습니다. 핵심은 transform-style: preserve-3d; 을 사용하는 것입니다. 그래야 3D 효과가 물씬 느껴지거든요. 말이 필요없지요? 바로 미리보기로 살펴보시겠습니다.

 

미리보기

See the Pen CSS : preserve-3d (A simple two-dimensional representation) (단순 2단 입체 표현) by rgy0409 (@rgy0409) on CodePen.

 

마우스를 배너에 올려보시면 오른쪽으로 스윽 돌아가면서 가려져있던 왼쪽 배너 이미지가 출력되는 형태의 입체형 div를 구성해 보았습니다. 그러면 늘 그러했듯 그림으로 어떻게 이게 동작하는건지 원리를 살펴보도록 하겠습니다.

 

그림으로 보는 원리 이해

우선 3개의 div가 필요합니다. 첫번째 div는 부모요소이며 색이 들어간 두 개의 div가 실제로 보여지는 배너 역할의 자식 요소가 됩니다.

 

그리고 각 자식 레이어 div 두 개는 transform을 사용해서 회전시키고 위치를 이동시킬 것입니다. 가장 처음에 보여질 div는 여러분들의 마음입니다. 저는 두번째 div를 가장 처음에 보여지게 하려고 합니다. 따라서 기준 div 영역에서 Z축으로 이동시킵니다. 첫번째 노란색 div는 기준 div를 기준으로 X축의 왼쪽으로 이동시킨 후 시계 방향으로 90도 돌려줄겁니다. 중심축을 이동시키는 규칙은 기준 div의 가로 길이의 절반(50%)만큼 이동시키면 됩니다.

 

그러면 최종 완성형태는 위의 이미지처럼 될 것입니다. 노란색 div의 오른쪽 모서리와 빨간색 div의 왼쪽 모서리가 딱 맞물리게 됩니다. 이 상태에서 기준 div를 마우스 호버 시 Y축을 기준으로 돌려주면 입체형태로 돌아가는 효과가 연출되는 것입니다.

 

HTML 뼈대

<body>
    <div id="wrap">
        <div class="card">
            <div>RIGHT</div>
            <div>LEFT</div>
        </div>
    </div>
</body>

먼저 HTML 태그는 이렇게 간단하게 구성되어 있습니다. 별거없죠? card 클래스명의 div가 위의 그림에서 회색 사각형인 기준 div가 됩니다. 그리고 그 안의 두 개의 div 자식 요소가 각각 LEFT, RIGHT가 됩니다.

 

CSS 스타일시트

자세한 CSS 코드는 위의 미리보기에 다 나와있으니 참고하시기 바랍니다. 여기에서는 부분 설명을 하겠습니다.

 

#wrap {
    width: 200px;
    height: 400px;
    margin: 100px auto;
    perspective: 700px;
    cursor: pointer;
}

먼저 최종 부모 요소인 #wrap ID값을 가진 div에는 입체 효과를 표현하기 위해서 perspective: 700px; 옵션이 사용되었습니다. 값이 작을수록 시야가 오브젝트와 가까워지기에 더욱 역동적으로 움직이게 되며 값이 커질수록 오브젝트에서 시야가 멀어지기에 작아지며 움직임의 강도도 작아집니다.

 

#wrap .card {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    transition: all 1.5s;
    transform-style: preserve-3d;
}

다음은 기준 div 영역입니다. 위치 초기화를 위해서, 그리고 자식 요소들까지 모두 겹치게 하기 위해서 position: absolute를 사용합니다. top과 left는 각각 0값이구요. 가로, 세로 크기는 #wrap의 크기를 따르기에 모두 100%라고 입력했습니다. 또한 이 기준 div가 실제로 입체 효과가 표현되어야 하기에 transform-style: preserve-3d; 을 반드시 마크업 해야합니다. 이게 없으면 3D 효과가 사라집니다.

 

#wrap .card > div {
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 100%;
    font-size: 20px;
}

여기는 딱히 중요한 부분은 없습니다. 기준 div의 각 자식 요소에 대한 위치값을 마찬가지로 position: absolute를 써서 서로 겹치게 만들었습니다. display: flex는 텍스트를 중앙 정렬하기 위해서 사용했습니다. 3D효과와는 무관합니다.

 

#wrap .card > div:nth-child(1) {
    transform: translateZ(100px);
    background-color: #f54;
}

#wrap .card > div:nth-child(2) {
    transform: translateX(-100px) rotateY(-90deg);
    background-color: #ed0;
}

그리고 기준 div의 각 자식 요소의 위치는 위의 CSS 스타일에서 정의하고 있습니다. transform을 사용해서 위치를 수동 이동시켰습니다. translate 값은 #wrap의 가로 사이즈를 기준으로 50%만 적용시키면 됩니다. 만약 배너 가로 크기가 300px이라면 회전축의 중심부터 가로 끝까지는 150px이므로 이 길이만큼 Z축으로 당기면 육면체의 한 면으로 자리가 잡힐 것입니다. 미리보기에서는 가로가 200px짜리 배너이므로 절반인 100px만 translate에 입력한 것입니다. 첫번째 div는 가장 처음에 보여지는 요소로 모니터의 정면으로 나오도록 위치 정렬을 위해 Z축을 사용한 것입니다. 두번째 div는 기본 상태가 왼쪽에 위치해있으며 동시에 90도가 돌아간 상태여서 X축으로 이동시키고 rotateY를 사용해 90도로 돌렸습니다. 음수는 Z축을 기준으로 살펴볼 때 오른쪽으로, 양수는 왼쪽으로 회전합니다.

 

#wrap:hover .card {
    transform: rotateY(90deg);
}

이제 위치 정렬은 다 되었으니 나머지는 간단합니다. 기준 div를 돌리면 나머지 자식 요소들도 절대 위치에서 그대로 위치해 있기에 부모 요소를 기준으로 돌아갈 것입니다. 그래서 전체 영역을 다스리고 있는 #wrap에 hover를 해주면 card 클래스명의 기준 div가 Y축을 기준으로 90도 돌아갑니다. 끝.

공유하기

facebook twitter kakaoTalk kakaostory naver band