CSS - animation, perspective

HyunHo Lee·2021년 11월 9일
6
post-thumbnail

keyframes

keyframes은 animation이 만들어지는 부분이다. from ~ to 를 이용한 방식과 0% ~ 100% 와 같이 퍼센트를 이용한 방식이 있다.


@keyframes turn {
  0% {
    background-color: red;
    transform: translate(0, 0);
  }

  100% {
    background-color: blue;
    transform: translate(300px, 0) rotate(360deg) scale(2);
  }
}

keyframes의 이름은 숫자, 영어 대문자로 시작할 수 없고, 특수문자를 사용할 수 없다. 위의 예시에서는 turn으로 생성했다.

0%에서 red이고, 100%에서 blue이므로 빨간색에서 파란색으로 변하면서 끝날 것이다. 위치는 300px만큼 x축 방향으로 움직일 것이며, scale(2)를 주었으므로 크기가 커지고, rotate(360deg) 으로 인해 빙글빙글 돌 것이다.


div {
  margin: 200px;
  width: 100px;
  height: 100px;
  background-color: red;
animation: turn 2s;
}

위에서 만든 keyframes를 div에 animation: turn 2s을 사용하여 적용시켰다. 2초 동안 animation은 완료된다.

최종으로는 위 사진의 파란 상자와 같이 될 것이다.
(infinite을 주면 animation을 반복시킬 수 있다.)


그 외 animation의 속성

  • animation-timing-function: 애니메이션 속도 조절
    linear | ease | ease-in | ease-out | ease-in-out | cubic-bezier

  • animation-delay: 애니메이션이 시작하기 전 지연시간

  • animation-iteration-count: 반복 횟수

  • animation-direction: 루프 (loop) 방향. 정방향으로 반복, 역방향으로 반복, 번갈아가며 반복 등을 설정

  • animation-fill-mode: 애니메이션 시작/끝 상태 제어
    none | forwards | backwards | both


스타벅스 빌딩

현재 위의 사진에서는 완성된 스타벅스 빌딩이 보인다. Animation을 이용하여 이 건물이 점점 쌓여서 완성되는 모습을 표현할 수 있다.

스타벅스 건물이 있는 부분을 빨간색 사각형이라고 보자. 우리에게 보이는 곳이다. 그리고 파란색 끈에 스타벅스 빌딩이 조금씩 지어지는 것을 쭉 그려준다. 이제 이 파란색 끈을 왼쪽으로 당겨보자.

스타벅스 빌딩 그림이 빠르게 지나가면서 결국 완성될 것이다. 하지만 이 경우에는 우리가 원하는 결과가 아니다. 쌓이는 모습만 보고싶지 지나가는 모습은 보고싶지 않다. 이 부분을 steps으로 처리해 준 것이다.

건물이 완성되고, 그 모습을 유지하기 위해서 fill-mode를 이용해주었다.

글자 슬라이드

    <div class="name">
        오늘 저녁
        <div class="name-job">
            <ul class="name-job-list">
                <li>김치찌개</li>
                <li>갈비찜</li>
                <li>라면</li>
                <li>치킨</li>
                <li>김치찌개</li>
            </ul>
        </div>
        <h2 class="name-title">먹자</h2>
    </div>

HTML 구조는 위와 같다.

        .name-job-list {
            animation: ani 4s infinite reverse;
        }

animation을 keyframes으로 생성해주고, name-job-list에서 infinite하게 실행해준다.

        .name-job {
            overflow: hidden;
        }

name-job에서 overflow: hidden; 옵션을 준다.

hidden 속성을 부여하지 않으면, 위와 같이 동작한다.

전체 코드는 GitHub를 참고하자.


perspective

    <div class="original">
        <div class="box"></div>
    </div>
        .original {
            width: 200px;
            height: 200px;
            border: 1px solid black;
            margin: 100px auto;
            perspective: 400px;
        }

        .box {
            width: 200px;
            height: 200px;
            background: red;
        }

현재 위와같이 box가 하나 있다. perspective는 원근감을 주기 위한 값이다. 밑에 예제에서 더 알아보자.


transform: rotateX(45deg);을 box에 넣어주자.
살짝 기울어진 것 같은 느낌이 든다.


perspective 값이 낮아지면 눈앞에서 기울인것처럼 기울어진게 확실하게 보여진다. 값이 작으면 작을수록 더 가까이서 보는것과 같은 원리이다.

perspective: 50px;을 주자. 기울어진 각도는 낮았지만 눈앞에서보니 효과가 크다.


transform: rotateY(45deg);을 주면 y축으로도 기울수 있다. (Z는 Z축..)


소실점 ( vanishing point )

    <div class="original">
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
        <div class="box"></div>
    </div>
        .original {
            display: flex;
            justify-content: space-between;
            width: 1000px;
            height: 200px;
            border: 1px solid black;
            margin: 100px auto;
            perspective: 400px;
        }

        .box {
            width: 200px;
            height: 200px;
            background: red;
            transform: rotateY(45deg);
        }

현재 box는 rotateY(45deg)을 동일하게 가지고 있다. 하지만 화면에서 보여지는 모습이 각각 전부 다르다.

perspective 속성을 부모에게 주어서 box마다 다른 perspective와 소실점을 가지고 있기 때문이다.

box에 개별적으로 perspective을 주기 위해서는 transform: perspective(400px) rotateY(45deg); 와 같이 사용하면 된다.

또는 perspective-origin을 사용해도 된다. default값은 perspective-origin: 50% 50%; 이다.

perspective 예제 사이트를 보며 감을 익히는게 좋을거 같다.


perspective 실습

<div class="scene">
  <div class="card">
    <img src="img/카드.jpg" class="item item_front">
    <img src="img/뒷면.jpg" class="item item_back">
  </div>
</div>

카드에 마우스를 가져다 대면, 돌면서 앞뒷면이 다르게 보이는 카드를 perspective를 이용하여 설계할 것이다.
이 링크를 참고했다.

        html, body{
            display: flex;
            justify-content: center;
            align-items: center;
            width: 100%;
            height: 100%;
        }

        .scene {
            width: 200px;
            height: 260px;
            perspective: 400px;
        }

        .card {
            width: 100%;
            height: 100%;
            position: relative;
            transform-style: preserve-3d;
        }

        .item {
            position: absolute;
            height: 100%;
            width: 100%;
            backface-visibility: hidden;
            transition: 1s;
        }
        .item_front {
            background: red;
            transform: rotateY( 180deg );
        }

        .item_back {
            background: blue;
            transform: rotateY( 0 );
        }

        .scene:hover .item_front{
            transform: rotateY(720deg) scale(2);
        }

        .scene:hover .item_back{
            transform: rotateY(540deg) scale(2);
        }

body에 크기를 주었고, flex 와 align-items 으로 보기 편하게 가운데로 정렬을 해주었다.

scene에 카드의 크기를 지정해주었다. perspective값은 400으로 주었다.

card에서는 부모의 크기 그대로 가져가기위해 100%로 설정하고, item들이 absolute하여 겹쳐질 수 있도록 relative를 사용했다. preserve-3d는 perspective를 부모로 부터 받아 자식요소에도 적용되도록 해준다.

item은 absolute가 되면서 카드의 앞면과 뒷면이 합쳐졌다. backface-visibility: hidden;는 3D transform에서 뒷면을 숨겨주는 역할을 한다.

처음에 카드의 뒷면을 보여주고, hover시 앞면이 보이도록 설정하기위해 rotateY() 값을 위와 같이 주었다.


hover 조건을 충족하면 한바퀴 반 돌면서 앞면을 보여주게 되고, 크기가 커진다.


마무리

perspective는 자세하게 파고들면 매우 어려울것이라고 생각한다. 재밌고 신기한 기능인 만큼 다루기가 까다로운 것 같다. 그래도 시간날때마다 여러가지 기능들을 사용해보며 역량을 늘려나가야겠다.

profile
함께 일하고 싶은 개발자가 되기 위해 달려나가고 있습니다.

9개의 댓글

comment-user-thumbnail
2021년 11월 9일

오 읽으면서 복습하는 시간을 가졌네요ㅎㅎㅎㅎㅎㅎ 오늘 하루도 수고하셨습니다👏

1개의 답글
comment-user-thumbnail
2021년 11월 9일

덕분에 복습했어요! 감사합니다

1개의 답글
comment-user-thumbnail
2021년 11월 9일

하루에 3편씩이나... 잘 보고 갑니다 항상 느끼지만 정말 잘 정리되어 있어서 도움이 많이 됩니다😊 오늘도 수고하셨습니다

1개의 답글
comment-user-thumbnail
2021년 11월 9일

저는 어려웠었는데.... 잘 정리하셨네요

1개의 답글