[Browser] 브라우저 렌더링, 리플로우, 리페인트

Bewell·2024년 3월 25일
0

Browser

목록 보기
1/1
post-thumbnail

브라우저 렌더링 과정

1. 브라우저는 어떻게 화면을 그릴까?

  • 주소를 입력해 사이트에 접속한다
  • 사이트 주소는 'https://www.naver.com' 형식으로 도메인 주소라 부른다

브라우저는 IP주소를 사용한다고 들었는데, 도메인 주소를 어떻게 IP주소로 바꿀까?

  • 사용자가 https://www.naver.com 도메인 주소에 접속한다
  • 이때 브라우저는 도메인주소로 네트워크 요청을 보낸다
  • 네트워크에서는 DNS서버를 사용해, 도메인 주소에 해당하는 IP주소를 찾는다
DNS란? (Domain Name System) 
- 도메인 이름('naver.com')을 IP주소로 바꿔주는 역할을 하는 시스템 계층
- 일종의 전화번호부 같은 역할
- 이로 인해 숫자로 되어 있는 IP주소를 기억하지 않고 해당 주소의 웹사이트에 접근할 수 있다.
  • 찾은 IP주소로 요청을 전송하여 도메인 주소에 해당하는 리소스(HTML)을 응답으로 받는다

도메인주소를 주면 도메인주소에 해당하는 IP주소를 찾아 리소스를 요청하는 방식
그렇다면 응답으로 온 리소스(HTML)은 어떻게 화면에 그려줄까?

  • 브라우저는 응답값 (HTML) 파일을 해석해서 화면을 렌더링하는데, 과정은 아래와 같다
  1. 브라우저는 DOM(Document Object Model), CSSOM(CSS Object Model)트리를 생성한다
- DOM은 XML, HTML문서에 접근하기 위한 인터페이지
- DOM은 자바스크립트로 접근하여 수정될 수 있다

- CSSOM은 CSS객체 모델로 자바스크립트가 CSS를 동적으로 조작할 수 있게 해준다
- CSSOM은 HTML대신 CSS가 타겟인 DOM이라고 할 수 있다
  1. 그 후 DOM, CSSOM트리를 결합하여 렌더트리를 만든다
    (이때, 렌더트리는 화면에 보이지 않는 요소는 제거, 예를들어 DOM트리의 html, head, meta 등의 비시각적 요소나 display: none 이 적용된 요소는 렌더트리에서 제외된다)
  2. 브라우저는 렌더트리를 기반으로 요소의 위치, 크기 등을 계산하는데, 이를 Layout 이라고 한다
  3. 마지막으로 요소에 스타일을 적용하는 Paint 과정을 거친다
  • 이처럼 브라우저는 트리 생상 -> Layout -> Paint 과정을 거처 화면을 렌더링한다


브라우저 렌더링과 reflow, repaint 관계

  • reflow, repaint를 알기위해, Layout, Paint 부분이 중요
  • Layout 은 앞서 설명했듯이 요소의 위치, 크기를 계산하여 화면에 그리는 과정인데, reflow와 관련있다
  • Paint는 배치된 요소에 스타일(색상, 굵기 등)을 적용하는 과정으로 repaint 와 관련있다
  • 우선 reflow는 말 그대로, flow 과정을 다시 하는 것

  • flow 작업은 곳 layout이며, reflow가 된다는 건, 요소의 위치, 크기계산을 다시 한다는 의미

  • repaintpaint를 다시 하는 것

  • paint는 요소에 스타일을 적용하는 과정, repaint는 요소의 스타일을 재적용하는걸 의미

  • 결국 relow, repaint는 브라우저 렌더링의 일부 과정을 다시하는걸 의미




reflow와 repaint

  • reflow, repaint는 요소가 시각적으로 변경되었을때, 변화를 계산하여 화면에 그려주는 작업이다
  • 만약 DOM이 시각적으로 변경되면 reflow가 발생하여 렌더트리를 재생성하고
  • 생성된 렌더트리를 기반으로 요소를 화면에 그리는 repaint가 발생한다


reflow

  • reflow는 요소의 너비, 높이, 위치 등이 변경되어 렌더트리를 재생성하는 작업

reflow 발생 시점

  • DOM 요소의 기하학적 속성이 변경될때 (width, height 등)
  • 브라우저 사이즈가 변경될때
  • reflow는 비용이 큰 작업인데, 그 이유는 특정 요소에서 reflow가 발생하면 주변 요소(부모, 자식, 형제)에도 영향을 주기 때문
  • JS에서 DOM관련 메서드를 실행하거나 DOM의 속성에 접근할 때도 발생한다
el.offsetLeft/offsetTop
el.offsetTop
el.offsetWidth/offsetHeight

el.getClientRects()
el.getBoundingClientRect()

window.scrollX/scrollY
window.innerWidth/innerHeight
window.getComputedStyle()


repaint

repaint 발생시점

  • reflow가 발생했을 때
  • 요소의 스타일이 변경되었을 때
  • visibility: hidden -> visible로 변경될 때
  • repaint는 스타일이 변경되었을때 발생하므로, reflow보다 비용이 적다
💡 visibility가 변경되는게 repaint라면, display:none도 repaint일까?

- visibility, display: none 둘 다 요소를 화면에서 숨기는건 유사하다
- 하지만 visibility는 공간을 차지하면서 보이지 않고, display:none은 영역도 차지하지 않는다
- 영역이 없다는건 "렌더트리에서 제외"된다는 의미이기에
- display가 변경되면 주변 요소의 위치, 크기에도 영향을 주어 reflow, repaint가 발생한다






reflow, repaint 줄이기

애니메이션 요소의 위치를 absolute로 적용

  • 애니메이션 요소의 위치변경은 주변요소에 영향을 미쳐 reflow가 여러번 발생한다
  • reflow가 여러번 발생하지 않도록, 애니메이션이 적용된 요소에 position: absolute를 적용하자

display:none 사용하기

  • display:none은 렌더트리에서 제외된다
  • 만약 요소의 여러 스타일 수정이 필요한 경우에는 display:none 적용 후 스타일을 변경, display:block하는 방법이 있다

DOM 속성 변경 코드 모으기

  • JS로 여러 DOM의 속성을 변경할 때 코드 순서에 따라 reflow횟수를 줄일 수 있다
// BAD - reflow 3회 발생
const el1 = document.querySelector('.target-first');
el1.style.width = '10px';

const el2 = document.querySelector('.target-second');
el2.style.width = '10px';

const el3 = document.querySelector('.target-third');
el3.style.width = '10px';


// GOOD - reflow 1회 발생
const el1 = document.querySelector('.target-first');
const el2 = document.querySelector('.target-second');
const el3 = document.querySelector('.target-third');

// dom의 스타일 변경 코드를 한 곳으로 모아둠
el1.style.width = '10px';
el2.style.width = '10px';
el3.style.width = '10px';
  • 코드 순서가 왜 reflow 횟수에 영향을 줄까?
  • 그 이유는 브라우저가 reflow를 처리하는 방식때문
  • 브라우저는 변경할 요소가 있을 때, 바로 처리하지 않고 큐에 저장한다
  • 그리고 일정 시간이 지나 reflow를 실행하기 때문이다

reflow 유발 함수의 호출을 제한하기

  • reflow를 발생시키는 함수나 속성을 매번 호출하지 않고, 변수로 저장하는 방식
// BAD
for (let i = 0; i< 10; i++) {
  el.style.width = target.offsetWidth + 10; // 반복문이 돌 때 매번 호출
}

// GOOD
const { offsetWidth } = target;  // 한 번 호출해서 변수에 저장
for (let i = 0; i< 10; i++) {
  el.style.width = offsetWidth + 10;
}

CSS로 스타일 한번에 변경하기

  • DOM의 여러 스타일을 변경해야 한다면, 스타일을 CSS 클래스로 정의해두고 한번에 변경하자
// BAD
el.style.width = "10px";
el.style.height = "10px";
el.style.borderRadius = "5px";
el.style.backgroundColor = "red";
el.style.left = "20px";


// GOOD
<body>
  <script>
    el.className = 'small';
  </script>
</body>

<style>
.small {
  width: 10px;
  height: 10px;
  border-radius: 5px;
  background-color: red;
  left: 20px;
}
</style>

가상 DOM 사용하기

  • DOM의 스타일이 변경될 때마다, 리렌더링이 발생하는 건 너무 비효율적이다
  • 만약 react, vue를 사용중이면, Virtual DOM이 비효율을 해소해줄 것 이다
  • 그 이유는, Virtual DOM은 생성한 DOM을 저장했다가, DOM에 변화가 있다면 메모리에 저장했던 DOM과 비교 후, 실제 변경된 DOM만 반영하기 때문이다
  • 결국 모든 DOM에 영향을 주지 않고 변경이 필요한 DOM만 바꾸기 때문에 리렌더링을 막을 수 있다

참고자료_1
참고자료_2
참고자료_3

0개의 댓글