Reflow/Repaint

Kychann·2025년 4월 18일
post-thumbnail

🖇️ 참조

lists.w3.org
Reflow, Repaint을 알아보자!

Reflow와 Repaint는 말 그대로 해당 요소를 다시 칠하고, 다시 플로우를 정하는 것이다.
최적화를 위해서 머리 빠지는 원인 중 하나이다.
Browser Rendering 에 대해서 알아야 한다.

HTML을 파싱해서 DOM tree를 만들고,
CSS를 파싱해서 CSSOM tree를 만든다.
이후 attachment라는 과정을 거치며 Render Tree라는 것을 생성해낸다.

그러고 나면, 오늘의 주제인 reflow 라는 것이 나온다.


Reflow(Layout)

레이아웃에서는 렌더 트리의 목적에 맞게, 각 요소의 구체적인 위치와 크기를 연산해낸다.
최신 브라우저는 이 과정 이후, update Layer Tree 를 생성해낸다고 한다.

결과적으로 보면, 이것을 브라우저에 픽셀을 렌더링 하는 페인팅 과정을 거치게 된다. 이를 위해 여기서는 각 노드를 거치면서 paint() 메소드를 호출한다. (여기가 Repaint() 와 사실상 대응)

이후에는 최신 브라우저의 경우 합성(Composite) 단계가 조건적으로 발생한다. 이 단계에서는 생성된 Layer들을 합성하여 단 한장의 비트맵으로 만들어 버린다.

각 Layer 별로 paint되기 때문에 불필요한 painting을 줄요 효율적으로 그릴 수 있다.


Reflow, Repaint발생

브라우저의 크기를 조절하거나 개발자의 의도에 따라 어떤 노드에 무엇을 추가하는 등, 브라우저에서 같은 스타일로 있지는 않는다.

이럴 때 발생하는 것이 ReflowRepaint이다.
만약 스타일이나 DOM 내부를 변경하는 DOM API가 사용됐다면, 우리의 DOM

  1. 뭔가 변경됐음을 감지
  2. 다시 위의 브라우저 작동 과정을 반복
  3. 리렌더링을 진행

(이러한 과정에서 리플로우와 리페인트가 발생하는 것이다.)

레이아웃의 경우 다음과 같이 PaintComposite과정 모두를 하게 된다.

JS, CSS Parsing → 렌더 트리 구축 → 레이아웃 → 리페인트 → 레이어 업데이터 → 합성

만약 리페인트만 한다면, 다음과 같다.

JS,CSS Parsing → 렌더 트리 구축 → 리페인트 → 레이어 업데이트 → 합성

만약 둘 다 필요 없는 스타일의 변화라면, 다음과 같다.

성능을 따지자면 가장 이상적이다!
JS,CSS 파싱 → 렌더 트리 구축 → 레이어 업데이트 → 합성

따라서 우리는 레이아웃과 리페인트가 일어나도록 유발하는 스타일 속성이 무엇인지를 인지해야 한다. 그냥 속성과 메소드를 사용했다는 이유만으로도, 리플로우가 발생하는 것들이 있다.


Reflow, Repaint 최소화

물론, 리플로우와 리페인트는 완전히 피할 수 없다. 그러나 최적화할 수 있다면 최대한 줄이는게 현명하다.

Repaint 의 경우, VisibilityDOM API 을 통해 조절했을 때 자식 노드들까지 다 검색하기 때문에 성능 저하를 발생시킬 수도 있다.

특히 Reflow 는 더 심각한 성능 저하를 만들기도 한다. 리플로우는 해당 요소의 자식 요소와 부모/조상 요소역시 레이아웃 계산을 진행해버리기 때문이다.

따라서 둘을 유발하는 스타일 속성 조정은, 만약 성능이 중요시 되는 애플리케이션이라면 고려해볼만한 최적화 요소이다.

🔥 대표적인 리플로우의 원인

  • 폰트의 변화 (height 계산에 영향을 주므로 Global Layout에 영향)
  • 윈도우 리사이징 (뷰포트 변화는 Global Layout에 영향을 준다.)
  • 스타일 추가 또는 제거(레이아웃을 바꾸므로)
  • 내용 변화(input에 텍스트 입력 등..)
  • hover와 같은 CSS Pseudo Class
  • Class Attrubute의 동적 변화
  • JS를 통한 DOM 동적 변화
  • 엘리먼트에 대한 offsetWidth / offsetHeight (화면에서 보여지는 좌표) 계산시
  • 스타일 Attribute 동적변화

너무나 많다. 특히 인터렉티브한 요소를 위한 제어라면, 이를 다 피할 수가 없다.
그렇지만 이를 인지하고 개발하는 것과, 모르고 개발한 결과물은 엄청난 차이가 존재할 것이다.
따라서, 이를 어떻게 앱에 활용할지를 고민해야 한다.

🌐 최대한 DOM 구조 상 말단 노드에만 클래스를 사용

  • 리플로우의 영향을 최소화하여 수행 비용을 줄인다.

🌐 인라인 스타일 자제

  • 인라인 스타일이 주어지면 리플로우가 수차례 발생하게 된다. 클래스를 사용하자.

🌐 애니메이션은 positionabsolutefixed 로 하자.

  • 주변 레이아웃 영향 X

🌐 퀄리티와 퍼포먼스를 타협

  • 애니메이션 계산, 페이지 Reflow에 대한 CPU 퍼포먼스 비용을 고려하자

🌐 테이블로 구성된 레이아웃 자제

  • 작은 변화도 테이블 전체 노드가 리플로우 발생

🌐 CSS에서 JS 표현식 자제

  • 문서중 일부가 Reflow될 때마다 표현식이 다시 계산되기 때문

🌐 CSS 하위 선택자는 필요한 만큼만 쓰자.

  • CSS Recalculation할 때, CSS Rule에 다라 오른쪽 → 좌쪽으로 매치시킬 Rule이 없거나 잘못된 Rule이 튀어나올 때까지 계속 매칭하기 때문이다.

🌐 일부 속성과 메서드는 자주 사용할 때 캐싱하자

  • 사용한다는 이유만으로도 리플로우가 발생하는 속성과 메서드가 있기 때문

🌐 position: relative; 주의

  • 일반적인 경우 Box model → Normal flow
  • position:absolute or fixed : Box model → Out of flow(Positioning)
  • position:relative : Box model → Normal flow → Positioning
profile
어,, 저 아닌데요?

0개의 댓글