만약 사용자가 브라우저 화면을 늘리거나 줄이는 등 크기를 조절하거나, 다른 사이트로 이동을 하는 등 화면에 요소가 추가 되거나 삭제, 혹은 아예 다른 요소들을 불러와야 하는 상황이 생기면 당연히 화면에 있던 요소들이 바뀌게 된다.
이렇게 화면에 나타나는 모습을 바꾸기 위해서는 모든 요소의 위치와 크기를 다시 계산하고, 다시 그려 보여주어야 한다. 이런 식으로 어떤 웹 인터랙션으로 인해 렌더링 과정의 레이아웃을 반복하는 것을 리플로우, 페인트 과정을 반복하는 것을 리페인트 라고 한다.
사용자의 눈에 일련의 과정이 부드럽게 처리 되려면 초당 60 프레임은 반드시 유지시켜야 한다.
즉, 1초라는 짧은 시간 안에 브라우저는 60번 가량의 레이아웃과 페인트 과정을 동시에 처리해야만 하는 것인데
여기서 중요한 점은 DOM은 변경이 되면 렌더 트리를 다시 구축하기 때문에, 변경이 될 때마다 리플로우와 리페인트를 다시 해야 한다는 것이다.
리플로우 하는 과정은 렌더링을 다시 하는 것이기 때문에 배치를 위한 연산을 해야 해 실제로 CPU를 많이 차지하고, 리페인트는 페인트를 다시 하는 것이라 픽셀을 다시 화면에 찍어 그려야 하기 때문에 GPU를 많이 차지한다. 때문에 프레임 드랍 현상과 직접적인 연관이 있다.
위의 사진은 프레임 드랍의 극단적인 예시 이다. 프레임 드랍은 초당 60프레임으로 유지시키던 프레임의 수가 브라우저의 과부하로 인해 줄어드는 현상을 뜻한다. 즉 없어진 프레임은 렌더링 엔진이 인식할 수 없다.
프레임 드랍 현상이 생기면 유저 경험(UX)에 좋지 않기 때문에, 최적화를 고려해야만 한다.
불필요한 레이아웃 하나만 줄여도 렌더링 퍼포먼스를 최적화할 수 있다.
CSSOM 트리의 CSS 속성 중에 레이아웃을 발생시키는 속성들이 존재하고 있다. 이 속성을 사용하게 되면 그때마다 변경이 되어 렌더 트리를 만들고, 레이아웃을 발생시키고, 페인트를 하는 과정이 연속적으로 발생한다.
따라서 이런 레이아웃을 발생시키는 속성을 피하면 해당 과정이 발생하는 횟수를 줄일 수 있다.
레이아웃과 페인트 과정은 별개의 과정처럼 보일 수 있으나 리플로우 시 리페인트는 필연적으로 일어나므로 가능하다면 리플로우가 발생하는 속성보다 리페인트만 발생하는 속성을 사용해주는 것이 좋다.
대개 위치, 혹은 너비와 관련된 속성이 많다.
position 속성의 left-top, left-bottom 속성은 레이아웃을 발생시키는 속성이다.
이 속성을 피해 transform 이라는 속성을 사용한다. transform 에 있는 translate을 사용하면 좌표 값을 사용해 위치를 이동하기 때문에 레이아웃을 발생시키지 않는다.
리페인트가 일어나지 않게 해주는 opacity라는 속성도 있다. visibility/display 보다 opacity를 사용하는 것이 성능 개선에 도움이 된다.
JavaScript + CSS를 조합한 애니메이션이 많거나, 레이아웃 변화가 많은 요소의 경우 position을 absolute 또는 fixed를 사용해주면 영향을 받는 주변 노드들을 줄여줄 수 있다. fixed 와 같이 영향을 받는 노드가 전혀 없는 경우 리플로우 과정이 필요 없기 때문에 리페인트 연산 비용만 들일 수 있다.