7편 애니메이션 최적화

2021. 4. 2. 07:29javascript/최적화

7편 애니메이션 최적화

애니메이션 최적화에 대해서 알아보기 전에 브라우저가 어떻게 렌더링을 하는지 알아봐야 합니다. 

 

애니메이션 작동 방법 

애니메이션의 경우에는 이미지를 조합해서 나타낸다. 

 

위와 같은 이미지들이 빠르게 순서대로 진행되며 만화와 같은 애니메이션으로 보이게 하는 것입니다. 

 

그래서 일반적인 모니터의 경우에는 1초의 60FPS(1초에 이미지를 표현할 수 있는 개수)로 이미지를 표현할 수 있다. 요즘 비싼 모니터의 경우에는 144FPS까지 가능하다. 

참고 영상

위의 동영상을 보면 알겠지만 1초에 얼마나 많은 이미지를 표현할 수 있냐에 따라서 애니메이션의 부드러움의 차이가 큰 것을 확인할 수 있다. 

 

하지만 브라우저가 특정한 이유를 통해서 한번의 이미지를 표현할 수 있는 프레임이 작아진다면 30FPS, 20FPS가 된다면 이미지가 버벅이는 쟁크 현상이 발생하게 됩니다.

 

브라우저에서 쟁크현상이 발생하는 이유

브라우저에서 쟁크현상이 발생하는 이유를 알려면 브라우저가 렌더링을 어떻게 진행하는지 알아야한다. 

1. 우선 HTML과 CSS를 파싱하여 각각의 모델로 만들어줍니다. (DOM, CSSOM)


각 모델은 Tree 구조로 되어있습니다.

2. Render Tree

 

위와 같이 RenderTree로 만들어줍니다. 

 

3. Layout

Layout Tree의 경우에는 위의 Rendering Tree를 기반으로 각 요소의 위치나 크기 등을 지정해줍니다. 

 

최종의 결과물은 아래와 같이 box 모형으로 나타냅니다.

4. Paint

 

Paint의 경우에는 각 색을 입히거나 그림자를 입히거나 하는 역할을 합니다.

 

5. Composite

 

Composite의 경우에는 위의 각 레이어에서 실행되는 각 층을 융합하는 과정입니다. 

 

 

이러한 과정을 일반적으로는 Critical Rendering Path 라고 한다.

 

만약 사이즈나 색이 변경된다면

 

만약 사이즈, 색 등의 스타일이 변형하게 된다면 Composite에서 첫 단계로 넘어가서 Rendering이 다시 실행되게 된다.

 

Reflow

Width, Height가 변경되면 위의 모든 과정이 다시 실행된다. Rendering 과정 중에서 특히나 Layout이나 Paint가 다시 실행되는데 이러면 컴퓨터의 자원을 많이 소비하게 된다. 

 

Repaint

color나 text Color 등이 변경되면 위의 과정 중 Layout을 제외하고 실행됩니다. 

 

Reflow, Repaint를 제외하고 애니메이션 실행하기

css요소 중 transform, opacity을 변경해주면 CPU 작업이 아닌 GPU가 작업을 대신하여 Layout과 Paint를 제외해서 훨씬 더 빠르게 Rendering을 해줄 수 있다. 

 

 

각 변경될 때 요소들

 

그래서 위와 같이 애니메이션의 요소가 에러나 렉이 걸릴경우는 무분별한 각 요소의 변경으로 Reflow가 발생한 것을 의심해볼 필요가 있습니다. 

 

우선 아래와 같은 에니메이션의 경우에는 performance로 확인해보면 아래와 같이 에니메이션이 진행된 것을 확인해볼 수 있다.

position: absolute;
    left: 0;
    top: 0;
    width: ${({width}) => width}%;
    transform-origin: center left;
    transition: width 1.5s ease;
    height: 100%;
    background: ${({isSelected}) => isSelected ? 'rgba(126, 198, 81, 0.7)' : 'rgb(198, 198, 198)'};
    z-index: 1;

 

아래와 같이 CSS 변경 후 진행 상황

 

아래의 경우에는 Reflow를 일으키는 width를 직접적으로 변경해주는 것이 아닌 Gpu 작업을 일으키는 transoform을 활용하여 에니메이션을 실행시켰다. 위의 경우에는 약 3초간 실행이 되었는데 아래의 경우에는 2.23초 정도가 실행되는 것을 알 수 있다. 

 

position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    transform: scaleX(${({width}) => width/100});
    transform-origin: center left;
    transition: transform 1.5s ease;
    height: 100%;
    background: ${({isSelected}) => isSelected ? 'rgba(126, 198, 81, 0.7)' : 'rgb(198, 198, 198)'};
    z-index: 1;