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

무한히 움직이는 원 애니메이션 (with, animation-delay)

by GicoMomg 2021. 10. 9.

이번 시간에는 animation-delay를 이용해 각각의 원이 다르게 움직이는 메이션을 만들어보았다.

1. preview

See the Pen infinite-circle by KumJungMin (@kumjungmin) on CodePen.



2. 코드 분석

1) html

  • center는 내부 자식들이 수직, 수평 중앙 정렬 시키기 위해 사용된다.
  • 화면에 보이는 여러 개의 원은 loader클래스의 자식이다.
  • 이 자식들(원)은 js를 이용하여 loader의 자식으로 추가할 예정이다!
    <div class="frame">
    <div class="center">
      <div class="loader"></div>   <!--여기에 원 추가 예정-->
    </div>
    </div>



2) js

  • 앞서 html파트에서 말했듯이 loader에 19개의 자식을 생성할 것이다.
  • 이 자식들은 circle클래스를 가지며, 움직이는 원 역할을 한다.
    const parent = document.querySelector(".loader");   //[1]
    for(let i=1; i<= 19; i++) {                         //[2]
    let circle = document.createElement("span");      //[3]
    circle.classList.add('circle');                   //[4]
    parent.appendChild(circle);                       //[5]
    }
    [1] 먼저, document.querySelectorloader을 가져온다.
    [2] 우리는 19개의 원을 만들 것이기에 for문을 사용한다.
    [3] document.createElement(span)으로 span 요소를 생성한다.
    [4] 3번에서 생성한 요소에 dom.classList.add('className')으로 클래스를 정의한다.
    [5] 마지막으로 parentDom.appendChild(dom)을 사용해 circle요소를 loader의 자식으로 추가한다.

앞선 과정을 거치면, 총 19개의 circle 클래스가 loader의 자식으로 추가된다! (와 편리행!)




3) scss

이제 필요한 요소는 다 생성했으니, 애니메이션의 핵심인 scss를 알아보자 🧐

(1) 요소를 중앙 배치시키기

A. frame을 화면 중앙에 위치시키기

  • 제일 루트 부모인 frame의 경우, 화면에서 수평 수직 중앙을 해야한다.
  • 먼저 [그림 1] 처럼,positionabsolute로 두고, top & left 50%를 한다.
  • 그 다음 [그림2] 처럼 요소에translate(-50%,-50%)를 주어, 정중앙에 위치하게 한다.
.frame {
  width: 400px;
  height: 400px;
  position: absolute;    //this
  top: 50%;              //this
  left: 50%;             //this
  transform: translate(-50%,-50%);  //this
  border-radius: 5px;
  box-shadow: 4px 8px 16px 0 rgba(0,0,0,0.2);
  background: linear-gradient(to right, #f64f59, #c471ed, #12c2e9);
 }

B. center 내부 요소를 중앙에 위치시키기

  • 먼저, center의 display를 flex로 정의한다.
  • 그 다음 justify-content: center로 내부 요소를 수평 중앙 정렬한다.
  • 마지막으로, align-items: cetner로 지정하여 내부 요소를 수직 중앙 정렬하면 된다.
.center{
  display: flex;
  justify-content: center;
  align-items: center;
}



(2) circle의 부모인 loader에 사전 작업하기

A. 자식인 circle 끼리 겹칠 수 있게

: loader의 자식인 circle이 서로 겹칠 수 있어야 한다.
: 그러기 위해서는 circleposition:absolute여야 한다.
: 하지만 absolute가장 가깝고, 위치가 지정된 조상 요소를 기준으로 상대위치한다.
: 그러므로 부모인 loaderposition: relative로 설정해야 한다.

.loader {
  width: 300px;
  height: 300px;
  position: relative;       //this!
  ...
}

B. 자식들이 중앙 위치할 수 있게

: loader의 자식은 circle이 수직 수평 중앙 정렬하도록 아래 속성을 지정한다.

.loader {
  ...
  display: flex;            
  justify-content: center;  
  align-items: center;      
  ...
}

C. 자식에게 변형 효과 주기

: loader에 아래와 같은 속성을 부여하며 자식(circle)에게 변형 효과가 적용된다.

perspective transform-style
- 원근감을 주는 속성
- transform과 같이 써야함
- 이 속성은 바로 아래의 자식 요소에게만 적용
- 요소에 변형을 줄 때, 그 변환이 자식에게 적용될지 설정
- preserve-3d를 하면 자식들이 3d처럼 변형됨
.loader {
  ...
  transform-style: preserve-3d;    
  transform: perspective(500px);  
}

D. 회전 효과를 줘서, 자식이 기울어지게 하기

.loader {
  ...
  transform: perspective(500px) rotateX(60deg);   //추가!
}

단, perspective과 같이 써야 원근감있게 회전한다!! 아래 예시를 보면 알 수 있다 :)

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



(3) circle에 애니메이션 주기

A. circle에 기본 설정하기

  • [1] circle이 서로 겹칠 수 있게 position: absolute를 준다.
  • [2] border-radius: 50%를 해서 원으로 만든다.
.circle {
  position: absolute;   //[1]
  border: 4px solid #fff;
  border-radius: 50%;   //[2]
  ...
  box-shadow: 0 5px 3px #ededed;
  transition: 0.3s;
}

B. translateZ, animation 효과 주기

  • 원래, transformperspective + translateY를 주며 아래 그림처럼 된다.

  • 하지만, 우리는 circle의 부모에 rotateX를 주었기에, translateZ를 하면 위쪽으로 이동한다.

결국, 우리는 circletranslateZ이 바뀌는 효과를 주면 된다!


  • 먼저, @keyframe을 사용해 translateZ가 바뀌는 애니메이션을 만든다.

    @keyframes rotateCircle {
    0%,
    100% {
      transform: translateZ(-100px);
    }
    50% {
      transform: translateZ(100px);
    }
    }
  • 그 다음, animation속성에 해당 애니메이션명을 등록한다.

.circle {
  ...
  transform: translateZ(-100px);    //초기 Z 위치
  animation: rotateCircle 4s ease-in-out infinite;  
  // 애니메이션명, 재생시간, 효과가 천천히 시작하고 천천히 끝내기, 무한재생
}



(4) 여러 개의 circle에 다른 속성 주기

이제 마지막으로, 우리가 js로 만들었던 여러 개의 circle에 다른 width, height를 주고,
서로 다른 애니메이션 지연 시간을 주면 순차적으로 애니메이션이 시작한다!

  • [1] scss에서는 $variable를 하면 변수를 만들 수 있다.

  • [2] @for $i from start to end로 반복문을 사용한다. (start<= i < end)

    $total: 20;                     //[1] circle전체개수 + 1
    @for $i from 1 to $total {      //[2]  
    .circle:nth-of-type(#{$i}) {  //[3]
      width: 12px * $i;           //[4]
      height: 12px * $i;          //[4]
      animation-delay: 0.1s * $i; //[5]
    }
    }
  • [3] nth-of-type을 사용해 여러 개의 circle에 접근한다.

A:nth-child(n) A:nth-of-type(n)
부모의 n번째 자식인 A요소 n번째 형제인 A요소 (단, 같은 태그여야함)
  • [4] 넓이, 높이에 $i를 곱해서 서로 다른 값을 준다.
  • [5] animation-delay는 애니메이션 지연시간으로, $i를 곱해서 서로 다른 지연 시간을 준다. (이 속성을 주면, 순차적으로 애니메이션이 실행됨)





출처
아래 출처로 이동하면 더 많이 알 수 있다고? 좋은데!🤔🤔

반응형

댓글