무한히 움직이는 원 애니메이션 만들어보자!

gicomong·2021년 5월 22일
24

css animation

목록 보기
18/21
post-thumbnail

이번 시간에는 간단하게, 무한히 움직이는 원 애니메이션을 만들어보자 ^0^)/

1. preview

!codepen[kumjungmin/embed/vYxgwNj?height=481&theme-id=dark&default-tab=css,result]



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이다.
: 미리보기를 보면, 원(자식)들이 X축 방향으로 회전되어 있다.
: 이 효과를 주기 위해 loaderrotateX(60deg)를 줘야한다! |

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

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

!codepen[kumjungmin/embed/JjWWbmp?height=401&theme-id=dark&default-tab=css,result]



(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이 바뀌는 효과를 주면 된다. >_0)d


  • 먼저, @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를 곱해서 서로 다른 지연 시간을 준다. (이 속성을 주면, 순차적으로 애니메이션이 실행됨)





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

profile
⚠ 이 블로거는 퇴근 후 극심한 피로감 + 강렬한 휴식 욕구로 인해 일주일 이상 포스팅이 없을 수 있습니다. 하지만 항상 좋은 내용을 담고자 합니다🙇🏼

관심 있을 만한 포스트

6개의 댓글

comment-user-thumbnail
2021년 5월 23일

와! canvas 사용 없이 border-radius 50%만 줘서도 원을 만들 수 있군요... 움직이는 건 전부 canvas로 해왔는데 이렇게도 가능하네요! 잘 배우고 갑니다!

1개의 답글
comment-user-thumbnail
2021년 5월 25일

정민양!!! 대박 ! 너무 멋져유!

1개의 답글
comment-user-thumbnail
2021년 5월 26일

와.. 진짜 멋있네요.. 이건 실제 서비스에 적용해도 될 거 같은데요? 게임 애니메이션 같아요 대단하세요. 감사합니다

1개의 답글