매끄럽게 동작하는 브라우저 만들기 - 렌더링 최적화 Reflow, Repaint

2023.07.26
8분
댓글

브라우저 렌더링 최적화

브라우저 렌더링이 언제 실행되는지 아시나요?
우리가 웹 사이트를 처음 마주했을 때 딱 한 번만 실행되는 것일까요? 🤔

브라우저 렌더링은 특정 조건에 따라 반복적으로 실행이 됩니다.
그렇기 때문에 렌더링이 언제 발생하는지 알게되면 우리는 불필요한 렌더링을 막을 수가 있습니다.

지금부터 렌더링이 언제 발생되는지 알아보고 불필요한 렌더링을 최적화 할 방법에 대해 알아보겠습니다.


렌더링이 반복되는 경우

  1. 자바스크립트에 의한 노드 추가 또는 삭제

  2. 브라우저 창의 리사이징에 의한 뷰포트 크기 변경

  3. HTML 요소의 레이아웃에 변경을 발생시키는 스타일 변경

위의 경우에는 Layout 계산과 Paint 과정이 재차 실행되어 리렌더링이 발생하게 됩니다.

이 과정에서 Layout 계산을 다시 수행하는 것을 Reflow, 픽셀을 렌더링하는 Paint 작업을 다시 하는 것을 Repaint라고 합니다.

두 용어에 대해 조금 더 자세히 알아볼까요?


Reflow

  • DOM 요소의 위치와 크기를 다시 계산하는 Layout 과정입니다.
  • 렌더링 트리를 다시 생성하므로 부하가 크고, 상위 엘리먼트가 변경되면 하위 엘리먼트에도 영향을 끼칩니다.
  • 예시
    • 노드의 추가, 제거
    • 위치 변경, 크기 변경, 폰트 변경, 윈도우 리사이징

Reflow는 비싼 작업입니다 💸

여기서 주의해야할 점은 Reflow가 발생하면 Repaint까지 발생하게 되므로 큰 비용이
발생한다는 것입니다.

지난 시간에 배웠던 브라우저 렌더링 과정을 한 번 떠올려볼까요?

  • JS, CSS 파싱 -> 렌더 트리 구축 -> Layout(Reflow) -> Paint(Repaint) -> 레이어 업데이트 -> Composite

해당 흐름에 따라서 Reflow가 발생하면 Repaint와 Composite 과정을 모두 수행하게 됩니다.
따라서 성능에 문제가 있다면 가장 먼저 Reflow가 발생하고 있진 않는지 찾아보는게 필요합니다.


Repaint

  • Layout 과정에는 영향을 미치지 않고 변경된 요소를 화면에 그려줄 때 발생합니다.
  • 예시
    • visibility, background-color, color

만약 Repaint만 발생하게 된다면 Repaint와 Composite 과정만 거치게 되므로 Reflow 보다는 상대적으로 훨씬 가벼운 작업이라고 할 수 있습니다.

Okay!

아하, 정리하자면 Reflow는 위치와 크기를 계산하는 기하학적인 변화를 담당한다면
Repaint는 기하학적 변화 외의 눈으로 보여지는 부분만 변경되는 작업이군요!

그리고 Reflow는 Repaint까지 발생시키는 비싼 작업이니까, 되도록 Reflow가 발생하지 않도록 주의하는게 필요하겠네요.

거의 다 왔습니다!

이제 Reflow, Repaint를 최소화 하는 방법을 알아보면서 불필요한 렌더링을 줄여봅시다.


Reflow와 Repaint 최소화 하기

1. 영향받는 노드 최소화하기 (position fixed, absolute)

  • 상위 노드의 스타일을 변경하면 하위 노드에 모두 영향을 주게 됩니다.
  • 따라서 다른 엘리먼트 레이아웃에 영향을 주지 않는 fixed와 absolute 속성을 사용하면 비용을 줄일 수 있습니다.

2. 숨겨진 엘리먼트 수정

  • display: none의 경우 Reflow와 Repaint가 발생하지 않습니다.
  • 많은 수의 엘리먼트를 변경해야 할 경우, 숨겨진 상태에서 변경하고 다시 보이도록 display: none 속성을 설정하여 레이아웃 발생을 최대한 줄일 수 있습니다.
  • 주의: visibility: hidden의 경우 보이지 않기 때문에 Repaint는 발생하지 않지만 공간을 차지하기 때문에 Layout은 발생하게 됩니다.

3. transform, opacity 속성 사용하기

  • 두 속성은 reflow와 repaint가 일어나지 않는 속성입니다.
  • left, right 대신 transform 속성을 사용하고
  • visibility, display 대신 opacity 속성을 사용하면 reflow, repaint 발생을 최소화 할 수 있습니다.

4. 애니메이션 최적화

  • 한 프레임의 처리는 16ms(60fps) 내로 완료되어야 끊기는 현상 없이 자연스럽게 처리됩니다.
  • 자바스크립트에서 setTimeout을 이용하여 애니메이션을 구현한다면 이벤트 루프에 의해 딜레이가 생길 수 있고, 16ms 안에 실행하지 못 한다면 해당 프레임은 유실됩니다 😳
  • 이를 도와주는 것이 requestAnimationFrame() 메서드입니다.
    • 장점: 지연 및 블로킹 없이 일정한 간격으로 애니메이션을 수행할 수 있습니다.
    • 브라우저 프레임 속도(60fps)에 맞춰 애니메이션을 실행할 수 있도록 합니다.
    • 또 다른 장점으로는 페이지가 비활성 상태일 때 렌더링을 중지하는 것이 있습니다. 덕분에 CPU의 리소스와 배터리 수명을 낭비하지 않게 되죠.
    • 이와 달리 setTimeout은 백그라운드 상태일 때도 계속 실행됩니다.

글을 마치며

지금까지 Reflow, Repaint 발생을 최소화 하여 브라우저 렌더링을 최적화 하는 방법에 대해서 알아봤습니다.
앞으로 개발을 하면서 성능 최적화가 필요할 때 앞서 배웠던 렌더링 과정을 떠올리면 리렌더링 원인을 파악하는게 수월해지실 겁니다!