개발 기술/css 애니메이션 (with js)

카드 뒤집기 애니메이션

by GicoMomg 2021. 9. 30.

1. 미리보기

perspective, backface-visibility을 사용해 카드 뒤집기 애니메이션을 만들어보자!

See the Pen animation_rotate card by KumJungMin (@kumjungmin) on CodePen.



2. 코드 분석

1) html

(1) 기본 틀 준비하기

  • 카드 뒤집기 애니메이션을 위해 총 4개의 div를 준비한다.

  • 먼저 카드 앞면, 카드 뒷면 역할을 한 front, back 클래스 div가 필요하다.

  • 그리고 이 카드 앞뒤 div를 감싸는 하나의 div(wrap)를 준비한다.

  • 마지막으로 hover시, 이벤트 버벅거림을 막기위해 hover 감지용 부모(card)를 준비했다.

    <div class="card">
    <div class="wrap">
      <div class="front">
        <div class="street">
        </div>
        <img class="bycicle" src="" alt="Bicycle">
      </div>
      <div class="back">
        <div class="sky">
        </div>
        <img class="car" src="" alt="Helicopter">
      </div>
    
    </div>

(2) 배경 애니메이션 공간 확보하기

  • preview를 보면, 자전거, 비행기 카드에 각각 길, 구름 애니메이션이 있다.

  • 이 애니메이션이 실행될 공간 확보를 위해 div(street, sky)를 생성한다.

  • 나중에, js, scss를 사용해 street, sky에 각각 자식 div를 생성할 예정이다.

    <div class="card">
    <div class="wrap">
      <div class="front">
        <div class="street"></div>    <!--추가! 길 애니메이션 공간-->
        <img class="bycicle" src="" alt="Bicycle">
      </div>
      <div class="back">
        <div class="sky"></div>      <!--추가! 하늘 애니메이션 공간-->
        <img class="car" src="" alt="car">
      </div>
    
    </div>



2) js

(1) 애니메이션용 자식 div 추가하기

  • 길을 지나는 애니메이션을 위해 street 클래스에 15개의 road 자식 클래스를 추가해야한다.
  • [1] 먼저 document.createElement를 사용해 div를 생성한다.
  • [2] 생성한 div에 document.className을 사용해 클래스 이름을 정의한다.
  • [3] 마지막으로 parent.appendChild를 사용해 street의 자식으로 추가한다.
    const street = document.querySelector('.street');
    for (let i=1; i<15; i++) {
      const newDiv = document.createElement("div");   //[1]
      newDiv.className = `road road_${i}`;   //[2]
      street.appendChild(newDiv);            //[3]
    }

만약 div에 class이름 대신 id를 주고 싶다면 document.id = 'id이름'을 하면 된다!

  • 하늘을 지나는 애니메이션도 위와 같이 진행한다.
    const sky = document.querySelector('.sky');
    for (let i=1; i<15; i++) {
      const newDiv = document.createElement("div");  //div 추가 
      newDiv.className = `cloud cloud_${i}`;    //div에 class명 지정
      sky.appendChild(newDiv);                  //자식으로 추가
    }


3) scss

(1) 헬리콥터, 자전거에 반동 애니메이션 주기

  • @keyframe으로 애니메이션 만들기
    • scaleY를 사용해 요소의 크기를 y축을 기준으로 변경한다.
    • skew를 사용해 요소를 기울인다. (쌩쌩 달리는 듯한 느낌을 주기)
    • 마지막으로 margin-top효과를 주면 반동이 있는 애니메이션을 만들 수 있다.
@keyframes driving {
  0% {
    margin-top: 5px;   //위아래 움직이기
    transform: scaleY(0.95) skew(1deg);  //크기조절 & 기울기
  }
  100% {
     margin-top: 0px;  //위아래 움직이기
  } 
}

  • 애니메이션 적용하기
    • animation속성을 사용해 키프레임 애니메이션을 사용할 수 있다.
    • 아래 표는 animation의 여러 속성을 나타낸다.
속성 이름 설명
animation-name 애니메이션명
animation-duration 재생시간 기본값은 0초, 지정하지 않으면 효과가 나타나지 않음
animation-delay 지연 시간 이 시간이 흐른 뒤에야 애니메이션 시작
animation-iteration-count 반복 횟수 infinite로 설정시 애니메이션이 무한 반복
animation-direction 진행 방향 reverse & alternate로 설정가능
reverse를 하면 애니메이션의 진행 방향을 반대 방향으로 진행됨
animation-timing-function 시간당 속도 linear: 일정하게
ease : (기본값) 천천히 -> 빨라지고 -> 천천히 진행
ease-in : 천천히 시작
ease-out : 천천히 끝남
ease-in-out : 천천히 시작 -> 천천히 끝남
cubic-bezier(n,n,n,n) : 사용자가 정의한 cubic-bezier 함수로 진행

  • 이 여러 속성은 아래와 같이 한 줄로 작성이 가능하다(와! 편리해)

    animation: 이름 재생시간 시간당속도 지연시간 반복횟수 진행반향

  • keyframe으로 만든 애니메이션은 아래와 같이 한 줄로 적용했다.

    .bycicle,
    .car {
    position: relative;
    padding-top: 35px;
    animation: driving 0.7s infinite linear alternate;  //animation 지정
    }

(2) 구름, 길 애니메이션 만들기

  • street, sky 디자인 설정
    • street, sky 클래스에 많은 자식들이 있다.(js에서 만들었음)
    • 내부 자식들이 부모를 벗어났을 때 보이지 않도록 overflow:hidden을 한다.
.street,
.sky {
  position: absolute;
  bottom: 0;
  width: 100%;
  overflow: hidden;    //this!!
}
.street {
  height: 42px;
  background: #3b3b3b;
  border-radius: 0 0 12px 12px;
}
.sky {
  height: 150px;
  background: #ededed;
  border-radius: 12px;
}
.road,
.cloud {
  position: absolute;
  height: 1px;
  border-radius: 1px;
}

  • 애니메이션 만들기
    • 이 애니메이션은 오른쪽 -> 왼쪽으로 요소들을 이동시킨다.
    • 애니메이션을 적용할 때 infinite를 하면 무한히 앞으로 이동하는 느낌을 준다.
@keyframes bottom {
  100% {
    right: 300px;
  }
}

  • 여러 자식에 랜덤 값 주기
    • street의 자식 road_n, sky의 자식 cloud_n에 각기 다른 실행시간, 위치값을 줘야한다.
    • 각기 다른 시간, 길이, 위치값을 줘야 선들이 불규칙이게 움직인다.
    • random(N)은 1~N까지의 숫자를 반환하는 함수로, 랜덤값을 줄 수 있다.
    • @for $i from to N을 사용해 scss에서 반복문을 사용할 수 있다.
    • 이 반복문을 사용하면 15개에 달하는 자식 클래스를 일일이 작성하지 않아도 된다.
$total: 15;

@for $i from 1 to $total {
  .road_#{$i} {
    top: random(35) + px;
    right: 0;
    width: random(50) + px;
    border-bottom: random(2) + px solid #dbdbdb;
    transition: 3s;
    animation: bottom random(40) * 0.1 + 0.3 + s linear infinite;
  }
  .cloud_#{$i} {
    top: random(150) + px;
    right: 0;
    width: random(50) + px;
    border-bottom: random(2) + px solid #cfcfcf;
    transition: 3s;
    animation: bottom random(40) * 0.1 + 0.3 + s linear infinite;
  }
}

(3) 카드 뒤집기

  • front, back을 감싸는 부모에 특정 속성 부여하기
    • 카드 뒤집기 효과에서 중요한 세가지 속성이 있는데,
    • 아래 두가지 속성은 꼭 부모 단에서 지정해주어야 한다.
perspective transform-style
- 원근감을 주는 속성
- transform과 같이 써야함
- 이 속성은 바로 아래의 자식 요소에게만 적용
- 요소에 변형을 줄 때, 그 변환이 자식에게 적용될지 설정
- preserve-3d를 하면 자식들이 3d처럼 변형됨
- preserve-3d를 하면 요소가 입체적이 됨
.card,
.wrap{
  position: relative;
  width: 300px;
  height: 150px;
  border-radius: 12px;
  perspective: 350px;           //원근법 ,transform과 같이 사용 
}
.wrap {
  transition: 1.5s;  
  transform-style: preserve-3d; //부모의 효과가 -> 자식에게 3d효과로 작용
}

  • front, back에 backface-visibility 주기
    • 카드 뒤집기에서 중요한 마지막 속성은 backface-visibility이다.
    • 이 속성에 대한 설명은 아래와 같다.
속성 설명
backface-visibility 요소의 뒷쪽에서 앞면을 보여줄 지 결정
지정가능한 값: visible, hidden, initial, inherit
.back,
.front {
  ...
  -webkit-backface-visibility: hidden; //브라우저 호환성
  backface-visibility: hidden;
}

  • hover시 효과주기
    • 부모요소에 hover를 했을 때, wrap에 rotateX로 뒤집기 애니메이션을 준다.
.card {
  &:hover .wrap{
    transform: rotateX(180deg);
  }
}




출처

반응형

댓글