Reflow와 Repaint가 뭐지?

김민찬·2024년 7월 19일
post-thumbnail

발단

0년차 : LCP가 너무 크고 렌더링이 잦으니 최적화를 해야하지 않을까요?

업무가 쏟아지다 보니 최적화라는 단어와 팀이 점점 멀어지는 듯한 느낌을 받았다. 팀원 모두가 기능이 돌아가는 것처럼 보이기만 하면 더 이상 개발하지 않기 일쑤였고, 이런 일이 쌓이다보니 기술부채가 늘어나고 있다고 생각했다.

내가 생각하는 좋은 팀은 기능 공장이 아니라 점진적으로나마 발전하면서 더 나은 코드를 생산하는 단체라 생각하여 위와 같은 말을 내뱉었다.

bluredDependency

LCP의 경우는 번들 사이즈를 바탕으로 설명해서 어느 정도 공감대를 형성할 수 있었다. 필요할때마다 새롭게 설치해서 사용하는 라이브러리를 가능하면 최대한 줄일 수 있도록 협의할 수 있었다.

렌더링의 경우에는 다양한 케이스가 있겠지만 일단은 가장 제네릭한 reflow를 줄이는 방향으로 설명하고자 마음먹고 아래의 발표자료를 준비했었다.

용어정의

Reflow?

화면구조(Layout)이 변경되었을 때 뷰 포트 내에서 렌더 트리상 노드의 정확한 위치과 크기를 계산하는 과정이다. element의 reflow는 DOM에 있는 모든 하위, 상위 요소의 후속 리플로우를 유발한다.

  • 모든 엘리먼트의 위치나 길이, 크기 등등을 다시 계산하는 과정
  • 상위 엘리먼트를 변경시키면 하위 엘리먼트에도 영향을 끼침
  • render tree를 재생성하므로 부하가 크고 레이아웃에 영향을 줌
  • DOM노드를 추가, 제거 , 업데이트하는 경우 발생

Repaint(Redraw)?

화면에 가시성이 변하지만 레이아웃에 영향을 미치지 않는 요소의 외관을 변경할 때 발생한다.

  • 레이아웃에 영향을 주지않지만 눈에 보이는 요소들(background-color, color, visibility,..)이 변경
  • reflow 보다는 부하가 크지는 않음

브라우저 렌더링 과정과 Reflow & Repaint


출처 : Understanding Reflow and Repaint in the browser

  • 모두가 잘 아는 DOM과 CSSOM가 parsing 및 구성되어 render tree가 형성
  • render tree를 순회하면서 reflow가 발생
  • reflow의 결과물에 따라 repaint 또한 발생

Reflow와 Repaint가 모두 일어나는 경우

  • DOM 노드를 추가, 제거 업데이트하는 경우
  • DOM 요소의 위치 변경, 크기 변경 (margin, padding, border, width, height, 등..)
  • display : none으로 DOM 요소를 숨기는 경우
  • DOM 노드를 이동하거나 애니메이션을 생성하는 경우
  • 창 크기를 조정하는 경우 (Resizing)
  • 글꼴 스타일을 변경하는 경우
  • 스타일 시트를 추가하거나 제거하는 경우
  • DOM을 조작하는 스크립트를 수정하는 경우
  • offset, scrollTop, scrollLeft와 같은 계산된 스타일 정보 요청
  • 이미지  크기 변경

Repaint만 일어나는 경우

  • visibility :  hidden 으로 DOM 요소를 숨기는 경우
  • background-color, visibillty, outline 등의 스타일 변경

렌더링 최적화

CSS 수정 시 주의 사항

  • 스타일을 변경할 경우 가장 하위 노드의 클래스를 변경한다.
  • 인라인 스타일링 자제
  • CSS 하위 선택자를 최소화한다.
  • 숨겨진 노드의 스타일을 변경한다.
    • display:none으로 숨겨진 노드를 변경할 때는 Reflow가 발생하지 않습니다. 숨겨진 노드를 표시하기 전에 노드의 콘텐츠를 먼저 변경한 후 화면에 나타내면 Reflow를 줄일 수 있습니다.

DOM 변경사항을 일괄처리

  • documentFragment를 사용하여 DOM사용을 최소화한다. ( documentFragment는 DOM에 적용되기 전까지는 메모리상에만 존재)
  • display :none으로 요소를 숨기고 (1 reflow, 1 repaint) 변경사항 100개를 추가한 후 display를 복원한다. ( 총 2 reflow, 2 repaint)

계산된 스타일을 반복적으로 묻지 않고 변수에 캐싱

  • offset, scrollTop과 같은 계산된 스타일 정보를 요청할 때마다 정확한 정보를 제공하기 위해 큐를 비우고 모든 변경사항을 적용하기 때문에 스타일 정보를 변수에 저장하여 사용을 권장

영향받는 엘리먼트 제한하기

  • 애니메이션 효과는 많은 Reflow 비용이 발생
  • position 속성을 fixed 또는 absolute의 값을 줘서, 지정된 노드를 전체 노드에서 분리시켜 해당 노드만 Reflow가 발생하도록 제한해야 한다.

<table> 레이아웃을 피한다.

  • <table>은 점진적으로 렌더링 되지 않고 모두 로드되고 테이블 너비가 계산된 후 화면에 그려짐
  • 작은 변화만 있어도 전체 테이블이 reflow가 발생한다.
  • 데이터 표시 용도로 사용 시, table-layout:fixed를 사용하자.

IE의 CSS표현식을 사용하지 않는다.

  • Reflow가 발생할 때마다 자바스크립트 표현식이 다시 계산되기 때문이다.

노드복제

  • 변경하려는 요소의 노드를 복제한 후 복제된 노드에 필요한 작업을 실행하는 방법.
  • 복제된 노드는 DOM 트리에 추가된 상태가 아니므로 렌더링 성능에 영향을 줄 수 있는 작업을 실행하더라도 리플로나 리페인트가 발생하지 않는다.
  • 작업이 모두 완료된 이후 복제된 노드를 원래 노드와 치환해 DOM 트리에 변경된 사항이 적용되게하면 치환 시점에만 리플로우와 리페인트가 발생한다.
var element = document.getElementById("box1");
var clone = element.cloneNode(true);     // 원본 노드를 복제한다.

for(var i=0; i < 100; i++) {
    clone.style.width = i + "px";
}

// 변경된 복제 노드를 DOM 트리에 반영하기 위해 기존 노드와 치환한다.
parentNode.replaceChild(clone, element);

참고

Reflow, Repaint 와 7가지 렌더링 최적화방법

Reflow, Repaint을 알아보자!

[Browser] Reflow와 Repaint

profile
열심히 공부 중인 프론트엔드 개발자

0개의 댓글