그래프를 클릭하거나 페이지에 들어서면 애니메이션이 실행되는 페이지이다.
위의 이미지에서 Timings는 그래프를 클릭 할때마다 리액트 함수가 실행되는 타이밍을 보여주고 있으며 그 타이밍에 맞춰 브라우저에 화면을 그리는 작업을 수행하는 내용을 아래 에서 확인 할 수 있다.
Timings 아래 부분을 확대해 보았다. 애니메이션을 변경될때마다 브라우저에 렌더링 하는 과정을 반복하는 것을 확인 할 수 있다.
5번의 경우 점선이 그어져 있는데 이 점선은 브라우저 화면에 렌더링 화면이 노출되어야 하는 시점이다. 하지만 마지막 레이어 합성과정이 완료 되지 않은 상태로 보여 진다.
위와 같은 현상이 일어나면 프레임이 드랍되거나 쟁크 현상이 일어나 애니메이션이 매끄럽지 않다.
이럴때는 reflow을 일으키는 속성들 사용 보다는 repaint를 일으키는 속성이나 layout, paint 단계를 건너띌수 있는 transform 속성을 사용 하는 것이 좋다.
모든 단계를 재실행
color, background-color 등의 변경 작업이 들어 왔을 시에는 css가 변경 되었기 때문에 dom 트리와 cssom 트리를 다시 만들고 색만 변경되었기 때문에 크기와 위치를 조정하는 단계인 Layout은 전에 사용하던 위치와 크기 그대로를 재사용 하고 레이아웃 단계를 건너 뛴다.
transform과 opacity등의 GPU가 사용 관여할수 있는 속성들을 변경하면 layout, paint 단계를 생략 할 수 있다.
const BarGraph = styled.div`
position: absolute;
left: 0;
top: 0;
width: ${({width}) => width}%;
transition: width 1.5s ease;
height: 100%;
background: ${({isSelected}) => isSelected ? 'rgba(126, 198, 81, 0.7)' : 'rgb(198, 198, 198)'};
z-index: 1;
`
위 css는 width값을 이용하여 애니메이션을 적용하는 리액트의 스타일 컴포넌트이다. 이 내용을 scaleX
속성을 이용하여 변경하여 Reflow, Repaint 피하고 GPU 도움 받아 렌더링 하도록 변경한다.
const BarGraph = styled.div`
position: absolute;
left: 0;
top: 0;
width: 100%;
transform: scaleX(${(props => props.width / 100)});
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;
`
scaleX의 축은 가운데를 기준으로 스케일이 변경되기 때문에 transform-origin 속성을 추가하여 세로는 가운데로 가로는 왼쪽으로 스케일이 변경 되도록 수정한다.
또 애니메이션이 transform에 적용되도록 transition 속성의 값을 transform으로 변경하여 준다.
웹 브라우저는 호출 스택에 실행 컨텍스트가 존재하는 동안, 즉 실행 중인 함수가 존재하는 동안에는 먹통이 되어 버립니다. 브라우저는 60 프레임으로 애니메이션을 렌더링 하고 있는데 그래프의 애니메이션이 뚝뚝 끊기는 현상은 애니메이션을 렌더링 하는데 60 프레임을 넘어가 프레임 드롭 현상이 나타나는 것입니다. 이는 사용자 경험에 악영향을 미칠 수 있습니다.
따라서, 브라우저에서 동작하는 JavaScript 코드, 특히 사용자와의 상호작용을 위한 코드를 작성할 때에는 코드의 실행 시간이 얼마나 될지를 항상 염두에 두어야 합니다.
Reflow가 일어난 영역에서는 보라색과 초록색 등 메인 쓰레드의 역할이 매우 활발한 것을 볼 수 있다.
.
.
.
.
.