[Web] 브라우저 렌더링 과정은 어떻게 될까?

Goni·2022년 12월 1일
0

Web

목록 보기
3/4

[12월 5일의 물음표 / 브라우저 렌더링 과정]

브라우저 렌더링 과정은 크게 네가지로 이루어진다.

  1. 주소창에 www.github.com 입력

  2. 통신을 위해 DNS에서 해당 도메인(www.github.com)을 가진 IP를 가져온다.

  1. 해당 IP에 페이지를 요청하고 리소스 응답을 받는다.

  2. 응답 받은 리소스들로 렌더링을 진행한다.

각 단계별로 중요한 부분은 자세히 훑어보자.


2. DNS란?

Domain Name Server의 약자로, 'Domain Name: IP' 의 쌍으로 이루어진 서버이다.
(IP를 위한 전화번호부라고 이해하면 쉽다!)

그럼 각 클라이언트 마다 DNS가 존재하는가?

  • DNS는 주로 인터넷 서비스 제공업체(ISP), 케이블 인터넷 공급업체가 가진다.

3. 리소스 응답

HTML, CSS, JS, 이미지 파일 등 화면 렌더링에 필요한 리소스 파일을 전달받는다.


4. 렌더링

화면을 그리는 가장 중요한 과정이다. 세세하게 분석해보자.
여기서 파싱 이란 브라우저가 이해할 수 있는 자료구조 형태로 변환하는 과정을 의미한다.

  1. HTML 파싱
    HTML 태그를 파싱하여 DOM 트리를 생성한다.
    바이트 > 문자 > 토큰 > 노드 > DOM 의 순서를 가진다.

  2. CSS 파싱
    html파일에서 <link> 태그나 <style> 태그를 만나면 DOM 생성 정지 후 CSS 파싱을 시작하고 CSSOM(CSS Object Model)을 생성한다.
    HTML과 동일한 파싱 과정을 거친다.

  1. 렌더 트리 생성
    HTML 파싱 후 생성된 DOM 트리와 CSS 파싱 후 생성된 CSSOM을 결합'(Attachment)하여 렌더 트리를 생성한다.
    렌더 트리는 렌더링을 위한 트리 형태의 자료구조이다.
    브라우저 화면에 렌더링되는 노드로만 구성된다.
    (meta태그, script태그, css 속성{display: none}을 가진 노드들은 포함되지 않음)

  2. 레이아웃(Reflow)
    웹 화면 내에서 각 노드의 위치, 크기, 너비, 높이 등을 계산하고 화면에 배치하는 과정이다.
    (스크린 상 어느 공간에 위치할 지 결정)
    상대적인 값(rem, vw, % 등)은 절대단위인 px로 변환된다.

  3. 페인트(Rasterizing)
    배치 된 노드들을 실제 픽셀로 나타내는 과정이다.


TIP_1) Javascript와 CSS

렌더링 과정을 최적화하면 속도를 높여 사용성을 개선할 수 있다!

Javascript

JS는 파서 차단 리소스이기 때문에 파싱 도중 JS를 만나면 진행중인 파싱은 중지되고, JS엔진에게 권한을 넘겨 JS를 우선 파싱하고 실행한다.
즉, 모든 문서 파싱이 중단되기 때문에 <head>태그가 아닌 <body> 태그가 닫히기 바로 전에 사용하는 것이 좋다.
<script>태그에서 defer와 async 속성을 추가하면 문서 파싱이 완료된 이후 실행된다고 한다.

CSS

CSS는 렌더링 차단 리소스이다. 렌더링 시 반드시 필요한 리소스이기 때문에 빠르게 다운로드 하는 것이 좋다.
즉, <head> 태그 안에서 정의하여 빠르게 다운로드 하는 것이 중요하다.



TIP_2) Reflow와 Repaint

DOM 내부/API, 스타일 변경 시 렌더링 과정을 반복한다.
리렌더링 과정에서 Reflow와 Repaint가 발생한다.
Reflow와 Repaint 과정을 줄이면 성능 향상에 도움이 된다!

Reflow

DOM 요소의 속성이 변경될 때, 브라우저 사이즈 변경 시, 스타일 시트 로딩 시 발생하는 변화를 다시 계산하는 작업
주변의 모든 요소들이 영향을 받는다.(DOM 트리 전체에 해당)
=> 비용이 많이 드는 작업(해당 속성 참고)
Reflow가 호출되면 Repaint는 자동으로 호출된다.

Repaint

변경된 요소를 실제로 화면에 그려주는 작업이다.
Reflow 발생 시 필연적으로 발생하지만 기하학적인 변화가 아니기 때문에 상대적으로 가벼운 작업니다.

Reflow, Repaint 과정 줄이기

리플로우가 최소한으로 발생되게 코드를 작성해야 한다!

  1. DOM 속성 변경 코드 그룹핑
// Good - Reflow 1번 발생
const h1 = div1.clientHeight
const h2 = div1.clientHeight

h1.style.height = `${h1 + 10}px`
h2.style.height = `${h2 + 10}px`

// Bad - Reflow 2번 발생
const h1 = div1.clientHeight	// 최신 값에 영향을 미치기 때문에 큐에 쌓인 작업을 모두 비우고 진행
h1.style.height = `${h1 + 10}px`

const h2 = div1.clientHeight
h2.style.height = `${h2 + 10}px`
  • 브라우저 자체로 리플로우를 줄이기 위한 전략을 가진다.
    => 지금 당장 처리가 아닌, 큐에 저장한 후 일정 시간이 지나거나 처리할 변경 작업이 일정량 쌓였을 때 리플로우가 수행된다.

  1. Reflow 유발 메서드는 별도 저장하여 사용
// Good
let { left } = div1.getBoundingClientRect()
for (let i=1; i<10; i++) {
	div.style.left = `${left + i}px`
    left += i
}

// Bad
for (let i=1; i<10; i++) {
	div.style.left = `${div1.getBoundingClientRect().left + i}px`
    left += i
}
  • Reflow를 발생시키는 메서드, 프로퍼티는 매번 호출하지 말고 변수에 저장한 후 사용하자.

  1. CSS 수정은 일괄 변경
    스크립트로 CSS 속성을 여러번 수정하는 것은 그만큼 Reflow를 여러번 유발시킨다.
// Good
div.className = "my-div";
div.style.cssText = "width: 100px; height: 100px; ...";

// Bad
div.style.width = "100px";   		  		// reflow, repaint
div.style.height = "100px";   		  		// reflow, repaint
div.style.padding = "5px";   		  		// reflow, repaint
div.style.border = "5px solid blue";      	// reflow, repaint
div.style.backgroundColor = "black";      	// repaint
div.style.color = "white";		  			// repaint

  1. display: none 속성 이용
    { display: none } 속성은 렌더 트리에서 제외되기 때문에 기하학적 변화가 일어나도 Reflow나 Repaint는 발생하지 않는다.
div.style.display = 'none'

... div 스타일 속성 수정...

div.style.display = 'block'








참고
https://www.freecodecamp.org/news/web-page-rendering-on-the-browser-different-methods/
https://beomy.github.io/tech/browser/browser-rendering/
https://kwangsunny.tistory.com/42

0개의 댓글