Etc

TIL | Reflow, Repaint

Reflow, Repaint

JS 코드에 의해 DOM or CSSOM을 변경하는 DOM API가 사용될 경우, DOM or CSSOM이 변경된다. 이때 변경된 DOM과 CSSOM은 다시 렌더 트리로 결합되고 변경된 트리를 기반으로 레이아웃과 페인트 과정을 브라우저 화면에 다시 렌더링하게 되는데, 이러한 과정을 리플로우(Reflow), 리페인트(Repaint)라고 한다.

Reflow

레이아웃의 재계산하는 것을 말하며, 다음과 같이 레이아웃에 영향을 주는 변경이 발생한 경우에 한하여 재배치를 위한 위치 계산 작업이 이루어진다.

  • DOM 노드의 추가, 제거
  • DOM 노드의 위치 변경
  • DOM 노드의 크기 변경(margin, padding, border, width, height 등..)
  • CSS3 애니메이션과 트랜지션
  • 폰트 변경, 텍스트 내용 변경
  • 이미지 크기 변경
  • offset, scrollTop, scrollLeft과 같은 계산된 스타일 정보 요청
  • 페이지 초기 렌더링
  • 윈도우 리사이징
  • 기본적으로 화면의 구조가 바뀔 경우, Reflow, Repaint 모두 발생한다.

Repaint

재결합된 렌더 트리를 기반으로 다시 페인팅이 이루어지는 과정이다. Reflow 과정 다음에 필연적으로 발생하며, 다음과 같이 레이아웃에 변경이 일어나지 않는 변화가 일어날 경우 Repaint만 발생한다.

  • opacity
  • background-color
  • visibility
  • outline

Reflow 최적화

Repaint는, Reflow로 인해 변경된 레이아웃을 다시 그리는 과정이기 때문에, Reflow단계에서 화면 변화를 최소화시키는 최적화가 일어나야 한다. 해당 방법은 다음과 같다.

1. Use Best-Practice Layout Techniques

  • 인라인 스타일링은 HTML 파일이 다운로드가 될 때 레이아웃에 영향을 미치고 추가 reflow를 발생시킨다.
  • table의 경우, 파서가 각각의 cell 치수를 계산하기 위해 둘 이상의 path가 필요하므로
  • flexbox를 사용한 페이지의 레이아웃 또한 성능 이슈가 있을 수 있다. 이유는 flex의 위치와 치수가 HTML 파일이 다운로드가 될 때, 변경이 될 수 있기 때문이다.

2. CSS 규칙 최소화(Minimize the Number of CSS Rules)

  • CSS 규칙이 적을수록, reflow의 속도는 빨라진다. 또한 가능하다면 복잡한 CSS Selector의 사용을 피해야 한다. (필요한 CSS만 적절하게 이용한다는 뜻같다.)

3. DOM Depths 최소화(Minimize DOM depths)

  • DOM Depth를 최소화하도록 한다. 문서의 크기가 작고 얕을 수록, 보다 렌더링까지의 시간이 단축된다. 따라서 불필요한 래퍼 태그의 사용을 지양하도록 한다.

4. DOM Tree에서의 말단에서 클래스 변경(Update Classes Low in the DOM Tree)

  • 가능한 DOM Tree의 말단에서 클래스를 변경하도록 한다. 이는 reflow의 범위를 필요한 만큼의 노드로 제한할 수 있다. 본질적으로는, 부모 노드의 클래스를 변경할 때는 자식 요소에 대한 영향이 적을 경우에만 적용한다.

5. 복잡한 애니매이션의 제거(Remove Complex Animations From the Flow)

  • 복잡한 애니매이션이 적용된 노드의 경우, position: absolute, position: fixed:를 적용 및 전체 노드로부터 분리시킴으로써 다른 요소에 영향을 주지 않고 치수 및 위치를 조정함으로써 reflow를 줄일 수 있다.

6. 숨겨진 요소에 대한 변경(Modify Hidden Elements)

  • display: none로 숨겨진 요소는, 변경시 reflow, repaint를 유발하지 않는다. 때문에 숨겨진 노드를 표시하기 전에 콘텐츠를 먼저 변경한 후 화면에 block 처리를 함으로써 발생할 수 있는 reflow를 줄일 수 있다.

7. 요소들의 일괄 업데이트(update Elements in Batch)

  • 성능은 DOM 요소들을 한번에 일괄적으로 업데이트 시킴으로써 향상될 수 있다.
// DOM 선택 후, 스타일을 개별적으로 변경할 할 경우
var myelement = document.getElementById('myelement');
myelement.width = '100px';
myelement.height = '200px';
myelement.style.margin = '10px';
  • 위와 같이 스타일링을 개별적으로 적용해 줄 경우, 추가 reflow가 발생할 수 있기 때문에 성능에 좋지 않은 영향을 줄 수 있다. 따라서 아래와 같이 클래스를 추가함으로써 한번에 스타일링을 변경하는 것을 권장한다.
// class 추가를 통해 스타일링을 일괄적으로 변경할 경우
var myelement = document.getElementById('myelement');
myelement.classList.add('newstyles');
.newstyles {
  width: 100px;
  height: 200px;
  margin: 10px;
}
  • 또한 아래와 같이 createDocumentFragmentDOM메서드를 사용함으로써 노드의 사용을 최소화하여 reflow 비용을 줄일 수 있다.
var
 i, li,
 frag = document.createDocumentFragment(),
 ul = frag.appendChild(document.createElement('ul'));

for (i = 1; i <= 3; i++) {
 li = ul.appendChild(document.createElement('li'));
 li.textContent = 'item ' + i;
}

document.body.appendChild(frag);

8. 영향을 받는 요소에 대한 제한(Limit the Affected Elements)

  • 많은 양의 요소들이 영향을 받을 수 있는 상황을 피하도록 하자. 탭을 클릭하였을 때, 다른 콘텐츠 블록이 활성화 되는 탭 형식의 콘텐츠 컨트롤을 고려하자. 각 콘텐츠 높이가 다를 수록, 주변 요소에 영향을 미치기 때문에, 컨테이너의 고정 높이를 설정하거나 문서 흐름에서 컨트롤을 제거하여 성능을 향상시킬 수 있다.

9. 성능을 저하시키는 부드러운 애니매이션에 대한 인지(Recognize that Smoothness Compromises Performance)

  • 요소를 한번에 1픽셀씩 움직이는 것은 부드러워보일 수 있으나, 기기가 느릴 수록 어려움이 있을 수 있다. 요소를 프레임당 4픽셀 씩 이동시키려면, reflow 처리의 1/4이 필요하며 부드럽지 않을 수 있다.

10. 브라우저 툴을 통한 리페인팅 분석(Analyze Repaint Issues with Browser Tools)

  • 모든 메인 스트림 브라우저는, reflow가 어떻게 성능에 영향을 미치는지 알 수 있는 개발자 툴을 제공한다. Chrome, Safari, Opera같은 브라우저들은 타임라인 패널을 열고 브라우저의 활동을 기록하며, 이를 통해 reflow와 repaint의 체킹이 가능하다.


Reference

'Etc' 카테고리의 다른 글

TTF, OTF 폰트별 특징  (0) 2023.07.28
리액트와 함께하는 테스트 격리(번역)  (0) 2023.04.17
TIL | 패키지 잠금파일  (1) 2022.03.26
TIL | GraphQL Subscriptions  (0) 2022.03.13
TIL | Tailwind CSS  (0) 2022.03.10