Reflow & Repaint

EZ·2024년 7월 4일
0

FE

목록 보기
1/1
post-thumbnail

목차

브라우저 매커니즘

HTML_CSS_parsing

  1. DOM(Document Object Model) Tree 생성
  • Server->Client : URL 입력, HTML 코드등 데이터 수신
  • Browser parsing
    • HTML source -> Token : TagName, Attribute, AttributeValue
    • lexing : Token -> DOM Tree nodes -> logical tree (DOM)
  1. CSSOM(CSS Object Model) Tree 생성 : CSS 규칙에 따라 생성
  • logical tree인 DOM과 달리, JS를 통한 CSS 접근이 가능하다.
    • CSS에 대한 DOM개념
  • 사용자의 CSS read / write를 가능하게 한다.
  1. Browser rendering : merge to Render Tree(DOM Tree + CSSOM Tree)
  • DOM Tree root node부터 시작, element들이 visible한지, computed style이 무엇인지 도출
  • not visible한 element : 무시. <meta>, <script>, <link>, display: none; 등의 요소는 제외하고 구성됨
  • visible한 노드 : CSSOM에 맞춰 Rendering Tree에 구성 됨
  1. Reflow : visible한 node들에 대한 레이아웃을 계산한다.
  • ex) width, position, float
  1. Repaint : 병합된 Render Tree의 노드들을 화면에 픽셀로 표시
  • ex) opacity, color, background-color, visibility

💡 computed style?

  • CSS는 Cascading style sheet로, 선언 방식or위치에 따라 우선순위가 나뉜다.
  • 우선순위(inline > internal > external)에 따라 적용된 최종 style을 computed style이라고 한다.

코드 상에서의 발생

이러한 reflow, repaint는 이벤트가 일어나 화면이 변경되었을 때에도 발생한다.
코드와 함께 확인해보자.

let elStyle = document.body.style;

// dimension 상 변화 O + 화면상 변화 O => reflow + repaint
elStyle.padding = '15px 10px';
elStyle.border = '1px solid red';
elStyle.fontSize = '30px';

// dimension 상 변화 X + 화면상 변화 O => repaint only
elStyle.color = 'white';
elStyle.backgroundColor = 'black';

// element append : dimension상 변화 O + 화면상 변화 O => reflow + repaint
document.body.appendChild(document.createElement('H1'))

이와같이, DOM element의 구조적인 dimension 상 변화가 있다면 reflow, 화면상의 픽셀값이 변화하면 repaint가 일어나는 것을 확인할 수 있다.

그 외에도 JS에서 reflow/repaint 관련 syntax를 사용할 때에도 발생한다.

  • ex) getComputedStyle(), scroll(), .focus(), .style

개념을 알고 있어야 하는 이유

reflow, repaint의 발생 빈도를 줄이면 아래의 것들이 개선될 수 있다.

  • read/write 감소하며 최적화에 유리해짐
  • 웹 성능이 떨어질 경우, 발생 요소를 고려하여 문제를 해결할 수 있음
  • 클린 코드, 언어적인 활용과도 연관이 있기 때문에 코드 유지보수에도 일정 정도 도움이 될 것으로 예상

발생 빈도를 줄이려면

1. 가상 메모리 / 캐싱 활용하기 (JS 코드 요소 활용하기)

1-1. fragment 노드를 사용

  • 더 유연한 코드 작성이 가능하다. (실제로 DOM에 추가된 element가 아니기 때문에)
  • 속도 면에서는 접속 환경에 따른 차이가 발생할 수 있다, fragment 사용 시 효과는 미미한것 같다. (오히려 느릴 때도 있다)
const root = document.querySelector('#root');
// ex1. documentFragment 객체 사용하기
const fragment = new documentFragment();

fragment.append(document.createElement('h1'));
fragment.append(document.createElement('h2'));
fragment.append(document.createElement('h3'));

root.append(fragment);

두번째 예시는 ex1과 선언 방식만 다르고 거의 동일하다.

// ex2. createElement('fragment') 컴포넌트 활용하기
const fragment = document.createElement('fragment');

// ex1과 동일
fragment.append(document.createElement('h1'));
fragment.append(document.createElement('h2'));
fragment.append(document.createElement('h3'));

root.append(fragment); // ex1과 동일

세번째 예시는 ex1, ex2 비슷하지만, append할 요소들을 포괄하는 컴포넌트가 같이 추가된다는 차이점이 있다.

// ex3. fragment 사용 없이 가상 메모리 이용하기
const divEl = document.createElement('Div');

// ex1, ex2와 변수명만 다름
divEl.append(document.createElement('h1'));
divEl.append(document.createElement('h2'));
divEl.append(document.createElement('h3'));

root.append(divEl); // ex1, ex2와 변수명만 다름

1-2. 캐싱하기

같은 맥락으로, 변경사항이 여러번 발생하는 element라면 변수에 캐싱하는 것도 도움이 될것 같다.

  • class, cssText 사용하기

1-3. 주의할 점

해당 게시글이 참고한 github documnet에 따르면, 다음과 같은 유의점이 기재되어있다.

  • jQuery(${CSS_selector}) : :even, :has, :gt, :eq 피하기
    • 기피해야하는 이유? : 본인으로서는 정확히 알 수 없으나, 이하의 이유들로 추론된다.
      • 현존하는 Vanilla JS가 이미 충분히 직관적임 : querySelectorAll, Array.prototype.filter
      • jQuery라는 라이브러리를 사용 : 즉각적인 코드 실행이 아님
      • 명확하지 않은 선택범위 : 해당 관심사(concern)에 속하지 않는 범위의 파악이 어려움
      • 러프하게 이야기 하자면, '있는거 쓰지 뭐하러 굳이 직관적이지도 더 빠르지도 않는걸 쓰냐'는 느낌이지 않나 싶다.
  • 코드 상의 관심사(concern)는 최소 범위로 잡을 것

2. 가시적인 element 숨기기

Render Tree 구성은 보여지는 노드들을 대상인 점을 이용한다.
기본적으로 보여지지 않는 element들에 대해서는 미리 display: none;처리를 하거나, visible한 케이스를 분리해 주는 것도 도움이 될 것이다.

3. CSS 수정

  • 20개 미만의 사항이라면 css 파일보다는 <style> 태그 사용하기
  • inline style 피하기
  • position: absolute, position: fixed 등을 활용하기 : 리소스 감소에 도움을 준다.
profile
제가 필요한 것들을 기록합니다. 당신도 필요했던 것이라면 럭키!

0개의 댓글