국비교육(22-23)

111일차(1)/CSS(10) : 3차원 컨텐츠 만들기(3)

서리/Seori 2023. 3. 21. 00:40

111일차(1)/CSS(10) : 3차원 컨텐츠 만들기(3)

 

 

- 3d transform을 하려면 먼저 3차원 공간을 정의해야 한다.

- 그러고 나서 이 안에서 3차원 transform을 만든다.

 

- perspective (물체와 관찰자와의 거리), perspective-origin (관찰자의 위치 설정) 설정을 한다.

- 어떤 물건을 어디에서 바라보느냐에 따라 관점은 달라질 수 있다.

 

 

- 이 3차원 공간 안에서 3d transform을 하겠다고 선언하면 된다.

- 선언하는 방법은 transform-styletransform-origin 을 설정하면 된다.

 

 

- 이 파란 박스가 3차원 공간이다. 이 안에서 어떤 아이템을 3차원 transform하겠다!

- 지정한 개체를 rotateX(45deg) 한 상태이다. x축을 기준으로 45도 회전.

 

 

 

- 이 x축을 정면으로 바라본다고 하면 이 축은 . 모양으로 보일 것이다.

- 축을 정면으로 보았을 때 시계방향으로 45도 회전한 것(양수). 반시계방향은 - (음수)로 작성해주면 된다.

- 지정한 값이 양수냐 음수냐에 따라서 회전방향이 달라진다.

 

- y 축도 이와같다. 바라보는 위치에서 시계방향으로 움직이게 하기

 

 

- 이렇게 z축을 정면에서 바라보고 있는 형태이다.

- 이 xyz축이 만나는 지점도 우리가 결정할 수 있다. 이것이 transform-origin 이다.

 

 

- transform-origin: 50% 50%; 가 의미하는 값이 이것이다!

- xyz축이 교차하는 지점을 개체의 정가운데로 두겠다는 의미가 된다.

 

 

- 75% 로 지정해서 보면 3/4 지점 정도에 y축이 있다.

- 일반적으로 설정하는 값은 50%이다.

 

 

- 똑같이 transform 했지만 perspective-origin을 20% 20%로 지정해서 바라보면 이렇게 보인다.

- 관찰자가 물체를 지켜보는 위치!! 시선의 위치에 따라 보이는 모양이 달라진다.

- 이 시점도 일반적으로 설정하는 값은 50%이다.

 


 

* 카드 뒤집기 만들기

 

 

- div만들기! 가로/세로/높이를 정해서 만든 2개의 div를 일단 겹친 후, 하나를 뒤집을 것이다.

 (원래는 왼쪽 이미지처럼 쌓이지만 css를 사용하면 도형을 겹칠 수 있다)

 

- 특정 버튼을 누르면 이것을 180도로 돌려서 뒤집은 div가 똑바로 보이도록 할 예정!

- 그러면 카드 2장을 겹쳐놓고 카드의 앞뒷면을 뒤집는 것처럼 보인다.

 

 

Step05_3dCardFlip.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Step05_3dCardFlip.html</title>
    <style>
        .wrapper{
            perspective: 500%;
            perspective-origin: 50% 50%;
            width: 180px;
            height: 200px;
        }
        .target{
            transform-style: preserve-3d;
            transform-origin: 50% 50%;
            transition: transform 0.4s ease-out;
        }
        .target > div{
            position: absolute;
            top: 0;
            left: 0;
            width: 180px;
            height: 200px;
            backface-visibility: hidden;
            /* 글자를 div의 가운데 오도록 */
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 20px;
            font-weight: bold;
            color: white;
        }
        .front{
            background-color: orangered;
        }
        .back{
            background-color: cadetblue;
            transform: rotateY(180deg);
        }
    </style>
</head>
<body>
    <div class="container">
        <h3>카드 Flip 예제</h3>
        <div class="wrapper">
            <div class="target" id="myCard">
                <div class="front">front</div>
                <div class="back">back</div>
            </div>
        </div>
        <button id="flipBtn">뒤집기</button>
    </div>
    <!-- jquery 로딩 -->
    <script src="https://code.jquery.com/jquery-3.6.4.js"
        integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E="
            crossorigin="anonymous"></script>
    <script>        
        //y축 회전값을 관리할 변수를 만들고 초기값 0 대입
        let rY=0;
        $("#flipBtn").on("click", ()=>{
            rY += 180;
            $("#myCard").css("transform", "rotateY("+rY+"deg)");
        });

    </script>
</body>
</html>

 

.target > div{
        width: 200px;
        height: 200px;
    }

 

- target 안에 있는 div에 적용!

 

 

- 겹치는 방법 position absolute 를 적용하면 이렇게 겹쳐져서 하나인 것처럼 보인다.

- front와 back이 겹쳐진 모양!

 

.back{
    border: 1px solid blue;
    transform: rotateY(180deg);
}

 

- back을 Y축 기준으로 180도 뒤집어놓기

backface-visibility: hidden; 하면 뒷면이 보이지 않는다.(디폴트 값이 visible 이다)

- visible 상태는 투명한 유리에 글씨가 쓰여있는 것이라고 생각하면 된다.

 

 

- 부모 div를 뒤집으면 된다. 그럼 자식 div는 자연히 같이 따라온다.

 

 

- jquery로 작성. 클릭하면 부모div 를 180도 뒤집어준다.

- 이렇게 하면 클릭시 카드가 뒤집히게 된다.

 

- 단 이렇게 작성하면 한번만 가능하다.

 

 

- rotateY() 여기 들어가는 값은 0을 기준으로 절대적인 값을 가지는 것이다.

- 정상 위치로부터 180도를 회전시킨다는 것이지 180도를 계속 회전시킨다는 것이 아니다. 누적되는 값이 아니다!

 

 

- 변수를 만들어 클릭할 때마다 180도씩 추가되는 코드로 작성해준다.

 

 

- 클릭하면 inline CSS가 증가한다.(검사 창에서 확인가능!)

 

- if문으로 분기해서 0이면 180으로, 180이면 0으로 바꾸도록 작성해볼 수도 있다.

 

 

- 글자를 좌우 가운데로 오도록 지정하고 카드 색상을 지정해주면 더 카드를 뒤집는 효과처럼 보인다.

 

 

- 최종 결과물!

 

 

- 페이지 로딩 시점에 필요한 컨텐츠를 배열해두고,

 특정 시점에 타겟 안의 컨텐츠(target div)를 transform 시킨다.

 

- 특정 동작(버튼 클릭)을 하면 미리 배열된 상태를 유지하면서 움직인다. 

 배열되어 있는 자식 컨텐츠를 부모 컨텐츠를 사용해서 변화시키는 것이다.

 


 

* 회전하는 3D 큐브 만들기

 

 

 

- div 6개를 하나로 겹쳐놓고 시작해서, div를 하나하나 면에 맞춰 배치한다.

- 3d transform을 사용해서 최종적으로 큐브 형태로 만들 수 있도록!

 

- 만든 큐브 전체에 부모 div를 잡아두고 돌리면 큐브가 회전하도록 할 수도 있다.

 

 

- div가 겹쳐져있는데, 한 장을 뒤로 일정 양만큼 민다고 생각하기

- 그리고 90도 회전시키고 우측으로 밀기

 

- 이런 방식으로 5개를 배치할 예정! 

- 뒷면은 밀고 나서 180도 회전시키면 된다.

 

 

 

- 각각의 div는 고유한 좌표계를 가지고 있다.

- 물체를 움직이거나 회전시키면 이 좌표계도 따라서 움직인다!

 

- 그러면 3번째 이미지의 회전시킨 div를 오른쪽으로 평행이동 시킨다고 하면? z축 방향으로 밀어야 한다.

 

 

Step06_3dCube.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Step06_3dCube.html</title>
    <style>
        .wrapper{
            perspective: 500px;
            perspective-origin: 50% 50%;
        }
        .cube{
            width: 400px;
            height: 400px;
            margin: 0 auto;
            transform-style: preserve-3d;
            transform-origin: 50% 50%;
            transform: translateZ(-200px);
        }
        .cube > div{
            border: 2px solid palevioletred;
            position: absolute;
            top:0;
            left:0;
            width: 400px;
            height: 400px;
            background-color: antiquewhite;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 100px;
            font-weight: bold;
            opacity: 0.5;
        }

        .cube > div:nth-child(1){
            transform: translateZ(200px);
        }
        .cube > div:nth-child(2){
            transform: rotateY(90deg) translateZ(200px);
        }
        .cube > div:nth-child(3){
            transform: rotateY(180deg) translateZ(200px);
        }
        .cube > div:nth-child(4){
            transform: rotateY(270deg) translateZ(200px);
        }
        .cube > div:nth-child(5){
            transform: rotateX(90deg) translateZ(200px);
        }
        .cube > div:nth-child(6){
            transform: rotateX(-90deg) translateZ(200px);
        }
        /* .cube{
            transition: transform 0.4s ease-out;            
        }
        .cube:hover{
            transform: translateZ(-200px) rotateX(45deg) rotateY(90deg); 
        } */

        @keyframes rotateAni{
            0%{
                transform: translateZ(-200px) rotateX(0deg) rotateY(0deg);
            }
            100%{
                transform: translateZ(-200px) rotateX(360deg) rotateY(360deg);
            }
        }
        .cube:hover{
            animation: rotateAni 5s infinite linear alternate;
        }
    </style>
</head>
<body>
    <div class="container">
        <h3>3d cube 테스트</h3>
        <div class="wrapper">
            <div class="cube">
                <div>1</div>
                <div>2</div>
                <div>3</div>
                <div>4</div>
                <div>5</div>
                <div>6</div>
            </div>
        </div>
    </div>
</body>
</html>

 

 

- 이렇게 작성해서 tab으로 자동완성시키면 아래와 같이 작성된다. Emmet을 잘 활용하기

 

 

- 3차원 공간으로 만들 div 안에 div 6개를 만들어준다.

 

 

- cube의 자식 div에 적용할 css !

- 6개 div를 겹쳐놓고 하나씩 움직이게 할 것

 

 

 

 

.cube > div:nth-child(1)

- 자식 div 중 첫번째 것을 가리킨다!

 

 

- 사이즈가 너무 커져서 cube 를 -200px 만큼 뒤로 밀어주었다.

 

.cube > div:nth-child(2){
    transform: rotateY(90deg) translateZ(200px);
}

 

- 2번째 div를 회전시켜서 밀었다.어버린것(오른쪽 면)

 

 

.cube > div:nth-child(1){
    transform: translateZ(200px);
}
.cube > div:nth-child(2){
    transform: rotateY(90deg) translateZ(200px);
}
.cube > div:nth-child(3){
    transform: rotateY(180deg) translateZ(200px);
}
.cube > div:nth-child(4){
    transform: rotateY(270deg) translateZ(200px);
}
.cube > div:nth-child(5){
    transform: rotateX(90deg) translateZ(200px);
}
.cube > div:nth-child(6){
    transform: rotateX(-90deg) translateZ(200px);
}

 

- 같은 방식으로 전체를 적용하면 이런 도형이 된다.

 

 

 

- 1번 면은 앞으로 밀기 적용

 

 

 

 

.cube{
    transition: transform 0.4s ease-out;            
}
.cube:hover{
    transform: translateZ(-200px) rotateX(45deg); 
}

 

- 마우스를 올렸을 때 X축을 기준으로 45도 회전시키면 이렇게 보인다.

 


 

 

 

- @keyframes 를 사용해서 큐브에 애니메이션 적용하기

 

 

 

 

- 큐브가 무한히 회전하는 애니메이션으로 만들 수 있다.

 

 

- 5s alternate 로 지정했기 때문에 5초 이후에는 반대방향으로 진행된다.

- 0%와 100%를 왔다갔다 하게 된다.

 

 


 

* 클릭할 때마다 큐브 좌우로 회전시키기

 

Step06_example.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Step06_example.html</title>
    <style>
        .wrapper{
            perspective: 500px;
            perspective-origin: 50% 0%;
            height: 600px;
            border: 1px solid blue;
            padding-top: 100px;
            box-sizing: border-box; /* padding과 border를 width, height에 포함되도록 */
        }
        .cube{
            width: 400px;
            height: 400px;
            margin: 0 auto;
            transform-style: preserve-3d;
            transform-origin: 50% 50%;
            transform: translateZ(-200px);
        }
        .cube > div{
            border: 2px solid palevioletred;
            position: absolute;
            top:0;
            left:0;
            width: 400px;
            height: 400px;
            background-color: antiquewhite;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 100px;
            font-weight: bold;
            opacity: 0.5;
        }

        .cube > div:nth-child(1){
            transform: translateZ(200px);
        }
        .cube > div:nth-child(2){
            transform: rotateY(90deg) translateZ(200px);
        }
        .cube > div:nth-child(3){
            transform: rotateY(180deg) translateZ(200px);
        }
        .cube > div:nth-child(4){
            transform: rotateY(270deg) translateZ(200px);
        }
        
        .cube{
            transition: transform 0.4s ease-out;            
        }        
        nav{
            text-align: center;          
        }
        nav button{
            font-size: 40px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h3>3d cube 테스트</h3>
        <div class="wrapper">
            <div class="cube">
                <div>1</div>
                <div>2</div>
                <div>3</div>
                <div>4</div>                
            </div>
        </div>
        <nav>
            <button id="prevBtn">&laquo;</button>
            <button id="nextBtn">&raquo;</button>
        </nav>
    </div>
    <!-- jquery 로딩 -->
    <script src="https://code.jquery.com/jquery-3.6.4.js"
        integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E="
            crossorigin="anonymous"></script>
    <script>
        //위의 버튼을 눌렀을때 .cube를 90도씩 y축 기준으로 회전하도록 해보세요
        let rY=0;
        $("#prevBtn").click(()=>{
            rY -= 90;            
            $(".cube").css("transform", "translateZ(-200px) rotateY("+rY+"deg)");
        })
        $("#nextBtn").on("click", ()=>{
            rY += 90;
            $(".cube").css("transform", "translateZ(-200px) rotateY("+rY+"deg)");
        })
    </script>
</body>
</html>

 

 

- 이전 큐브 예제에서 그대로 복사해와서 div 4개만 남김

- 그러면 위, 아래는 뚫려있는 박스 형태가 된다.

 

 

- 버튼을 누르면 회전시킬 수 있도록 navbar에 좌,우 이동 버튼을 만들어준다.

 

- jquery에서 .on("click", xxx) 말고 바로 .click 을 사용해도 된다.

 

 

- 밀어놓고 회전을 시켜야하는데 밀어놓지 않았기 때문에 도형이 앞으로 튀어나온다.

- -200으로 배치해야 한다.

 

 

- 처음부터 위치값을 -200px로 조정해놓고 돌린다.

 

 

 

- 이제 화살표를 클릭하면 큐브를 한칸씩 좌/우로 빙글빙글 돌게 하는 효과를 낼 수 있다.