BoostCource/Front-end

[FE] 03. Web Animation 활용

칸타탓 2018. 7. 27. 17:24

3. 웹 애플리케이션 개발 - Web Animation

웹 애니메이션 이해와 setTimeout활용

1. 애니메이션

애니메이션은 반복적인 움직임의 처리를 말한다.

웹 UI 애니메이션은 자바스크립트로 다양하게 제어할 수 있지만, 칙적이고 비교적 단순한 방식으로 동작하는 방식은 CSS3의 transition과 transform속성을 사용해서 대부분 구현 가능하다.

 

이는 자바스크립트보다 더 빠른 성능을 보장하며 특히 모바일 웹에서는 CSS를 사용한 방법이 훨씬 더 빠르다.

 

2. FPS

FPS (frame per second): 1초당 화면에 표현할 수 있는 정지화면(frame) 수

매끄러운 애니메이션은 보통 60fps이므로 16.666밀리세컨드 간격으로 frame 생성이 필요하다. (1000ms / 60fps = 16.6666ms)

 

애니메이션은 CSS의 transition속성으로 CSS 속성을 변경하거나 JavaScript로 CSS 속성을 변경할 수 있다.

  • 간단하고 규칙적인 거 → CSS로 변경하기

  • 세밀한 조작이 필요한 거 → JavaScript로 변경하기

 

3. JavaScript 애니메이션

자바스크립트로 애니메이션을 구현하려면 규칙적인 처리를 하도록 구현한다.

  • setInterval

  • setTimeout

  • requestAnimationframe

  • Animations API

3.1 setInterval()

지정된 시간마다 반복 실행한다. (주어진 시간에 따라서 함수 실행 가능)

const interval = window.setInterval(()=> {
  console.log('현재시각은', new Date());
},1000/60);
 
window.clearInterval(interval);

 

하지만 지연문제가 발생할 수 있다.

아래 그림을 보면 제때 일어나야 할 이벤트 콜백이 지연되고 없어지는 것을 볼 수 있다. 그렇기 떄문에 setInterval을 사용한다고 해서 정해진 시간에 함수가 실행된다고 보장할 수 없다. 그 사이에 다른 작업이 일어나면 (타이머, 마우스 클릭 콜백 등) 비동기 작업이기 때문에 동기적인 다른 작업에 밀리기 때문이다.

애니매이션이 끊겨 보일 수 있기 때문에 일반적으로 setInterval을 사용하는 애니메이션 구현을 잘 하지 않는다.

따라서 3.2와 같은 방식으로 recursive하게 구현한다.

 

 

 3.2 setTimeout

지정된 시간 이후 한번만 실행한다.

//arrow 함수를 사용했어요.
  setTimeout(() => {
    console.log('현재시각은', new Date());
  },500);

 

애니메이션을 재귀호출을 사용해서 구현할 수 있다. 이 경우 스택 오버플로우가 발생하지 않는다.

let count = 0;
function animate() {   
  setTimeout(() => {
    if(count >= 20) return;
    console.log('현재시각은', new Date());
    count++;
    animate();
  },500);
}
animate();​

 

* setInterval , setTimeout 차이점

setTimeout도 어떤 이유로 인해 제때에 원하는 콜백함수가 실행되지 않을 수도 있다. 결국 setInterval과 같은 문제가 발생할 수도 있다.

하지만 setTimeout은 매 순간 timeout을 조절할 수 있는 코드구현으로 컨트롤 가능한 부분이 있다는 점이 setInterval과 큰 차이라고 할 수 있다.

이러한 setTimeout의 대안으로 나온 것이 다음의 requestAnimationFrame이다.

 [참고] https://javascript.info/settimeout-setinterval

 

 


 

* requestAnimationFrame

setTimeout이나 setInterval을 사용해서 연속적인 함수 호출로 애니메이션을 구현하는 방법은 약간의 delay가 발생하는 문제가 있다. 이 함수는 애니메이션을 위해서 생겨난 기능이 아니기 때문이다.

애니메이션 구현을 위해서는 끊김없이 부드럽게 처리가 되어야 하므로 이를 위한 메서드를 브라우저가 제공하고 있다.

 

setTimeout은 animation을 위한 최적화된 기능이라 보기 어렵다. animation주기를 16.6 미만으로 하는 경우 불필요한 frame 생성이 되는 등의 문제가 생긴다.

그 대안으로 생긴 것이 바로 requestAnimationFrame이다. (애니메이션을 위한 전용 함수)

 

requestAnimationFrame을 한번 실행시켜준다. 그 이후에 특정 조건이 될 때까지(함수의 탈출 조건) 계속 함수를 연속적으로 호출한다.

이렇게 requestAnimationFrame함수를 통해서 원하는 함수를 인자로 넣어주면, 브라우저는 인자로 받은 그 비동기 함수가 실행될 가장 적절한 타이밍에 실행시켜준다.

 

- 예제

var count = 0;
var el=document.querySelector(".outside");
el.style.left = "0px";

function run() {
   if(count > 70) return;
   count = count + 1;
   el.style.left =  parseInt(el.style.left) + count + "px";
   requestAnimationFrame(run);
}

requestAnimationFrame(run);

제에서는 연속적으로 requestAnimationFrame를 통해서 run함수를 호출하면서 left 값을 증가시켜주고 있다.

el.style.left인 경우는 왼쪽으로 이동하며, el.style.top인 경우는 위에서 아래로 떨어지는 형태이다. 이런식으로 애니메이션 속성을 바꿔가며 추가할 수 있다.

 

canvas, svg를 사용하면서 그래픽 작업을 하게 될 때 복잡한 애니메이션을 다룰 필요가 생길 수 있다.

자바스크립트로 복잡한 애니메이션처리를 처리해야 할 때 requestAnimationFrame은 꽤 유용하게 쓰인다.

 


 

* CSS transition

<style>
transform: scale(1);
transition: all 2s; //모든 속성을 2초 동안 변화시키도록 한다. (애니메이션 작동 시간을 조절하는 것!)
</style>

<script>
var base = document.querySelector(".outside");
base.style.transform = "scale(4)"; //크기 키우기
bale.style.left = "500px"; //왼쪽으로부터 이동하기
</script>

이 방법이 JavaScript로 구현하는 것보다 더 빠르다고 알려져 있다.

특히 모바일 웹에서는 transform을 사용한 element의 조작을 많이 구현한다. 

[참고] 링크 바로가기

 

* transition 사용 실습

버튼을 누르면 오른쪽으로 이동하도록 슬라이딩 UI 만들기.

(+) 참고로 CSS 속성은 base.style.transform = "scale(2)" 처럼 문자열로 들어가야 한다.

 

 

[참고] https://robots.thoughtbot.com/transitions-and-transforms

 


 

* 더 빠른 css3 애니메이션 관련 속성들

GPU가속을 이용하는 속성을 사용하면 애니메이션 처리가 빠르다. 메인 쓰레드에서 처리되는 것이 아닌 그래픽 처리를 GPU에게 위임하기 때문이다.

  • transform : translateXX();

  • transform : scale();

  • transform : rotate();

  • opacity