렌더링 (Rendering)

- 웹 개발을 하면서, 또는 그 웹을 사용하면서 우리는 알게모르게 렌더링을 많이 접하고 있어요. 중요한 내용이니 꼭 알고 넘어가도록 해요!

렌더링이란?

웹 브라우저는 HTML문서를 해석하고, 화면을 통해 해석된 결과를 보여줘요.

HTML, CSS, JavaScript 등 개발자가 작성한 문서를 브라우저에서 그래픽 형태로 출력해 주는 과정이 렌더링이에요.

웹 브라우저가 원본 HTML, CSS, JavaScript 문서를 읽어들인 후, 스타일을 입히고 대화형 페이지로 만들어 view port에 표시하기까지의 과정을 Critical Rendering Path라고 불러요.

브라우저마다 렌더링을 수행하는 렌더링 엔진이라는 것을 가지는데, 그 종류는 아래와 같아요.

  • 크롬 : 블링크(Blink)
  • 사파리 : 웹킷(Webkit)
  • 파이어폭스 : 게코(Gecko)

렌더링 과정

step
1

STEP 1

브라우저는 서버로부터 HTML, CSS 등 웹 사이트에 필요한 리소스를 다운로드 받아요. 이제 사용자에게 출력할 일만 남았어요.

이제 렌더링 엔진은 서버로부터 받은 데이터를 웹 표준화기구인 W3C명세에 따라 해석하는데, 이 해석 과정을 "파싱"이라고 불러요.

2

STEP 2

렌더링 엔진은 HTML 문서를 파싱하여, DOM 트리를 만들어요.

3

STEP 3

렌더링 엔진은 <style> 태그를 만난다면, HTML파싱 작업을 중지하고, CSS 파싱 작업을 시작하여, CSSOM 트리를 만들어요.

이 때, 스타일은 아래에 나열한 순서대로 적용되고, 나중에 처리된 스타일이 우선적으로 적용되요.

  • 브라우저의 자체 스타일
  • 사용자 정의 스타일
  • HTML태그에 적용된 스타일
4

STEP 4

DOM 트리와 CSSOM 트리를 결합해 렌더 트리를 형성해요. 렌더 트리를 생성하는 과정까지를 Construction이라고 해요.

  • 화면에 드러나지 않는 할당요소는 렌더 트리에 포함되지 않아요.
  • 렌더 트리에는 페이지를 렌더링 하는데 필요한 노드만 포함되요.
5

STEP 5

HTML 파싱 중, 자바스크립트를 의미하는 <script>태그를 만나게 되면, DOM파싱을 중지하고 자바스크립트 엔진에게 제어권한을 넘겨요. 그리고 스크립트를 모두 실행하면, 다시 DOM을 그리기 시작해요.

브라우저의 자바스크립트 엔진은 서버에서 응답한 자바스크립트를 파싱하여, AST(추상 구문 트리)를 생성하고, 바이트코드로 변환하여 실행해요.

  • 서버로부터 응답된 자바스크립트 코드는 각각의 의미를 갖는 토큰으로 분해되며, 이 토큰이 결합되어 AST를 형성해요.
  • 인터프리터는 생성된 AST를 가상머신이 이해할 수 있는 바이트코드로 변환해요.
  • 여기서, AST는 프로그램 내에서 발생하는 기능을 나타내기 위해 만들어진 구조화된 트리입니다.

이 때, 자바스크립트는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있으며, 변경된 DOM과 CSSOM은 다시 렌더링 트리로 결합되요.

이 부분에서 <script>의 위치에 대해 중요한 내용을 아래에 적어봤어요. 꼭 천천히 읽어보고 넘어가도록 해요.

  • HTML파싱은 위에서 아래로 동기적으로 이루어지기 때문에, HTML파싱은 <script>의 위치에 따라 지연될 수 있어요.
  • 자바스크립트 코드가 DOM, CSSOM을 변경하여 HTML노드를 생성하는 경우, HTML 파싱이 완료되어 있어야 하기 때문에, <script>는 되도록 <body>가 끝나는 부분에 위치하는 편이 좋을 수 있어요.
  • 하지만, <script>가 <body> 맨 아래에 위치할 때, 사용자가 자바스크립트 코드 파싱 중에 웹 상호작용을 시도한다면 비정상적으로 작동할 수 있어요.
  • 그렇기 때문에 브라우저는 스크립트 파일을 병렬로 불러오는 방식으로 DOM 렌더 과정을 막지 않게 선언할 수 있어요. 이를 가능하게 하는 키워드는 async, defer가 있어요.
  • async 스크립트는 <script>를 만나고, DOM 렌더 과정을 방해하지 않도록 스크립트 파일의 로딩을 병렬로 처리해요. 하지만, 파일의 로딩을 마치게 되면 그 즉시 DOM 렌더를 멈추고 async방식으로 불러온 스크립트 파일의 해석을 시작하기 때문에, 실행 순서가 보장되지 않아요. 불러온 스크립트 파일의 해석이 언제 끝날지 모르니까요!
  • defer 스크립트도 <script>를 만나고, DOM 렌더 과정을 방해하지 않도록 스크립트 파일의 로딩을 병렬로 처리해요. 하지만, defer 스크립트는 모든 DOM이 로드된 후에 실행되요. 또한, defer 스크립트는 선언한대로 실행순서가 보장되기 때문에, 실제도 더 빨리 로드된 스크립트가 있다 하더라도, 실행은 항상 선언한 순서대로 이루어져요.
  • 따라서, 기본적으로 DOM의 모든 엘리먼트에 접근할 수 있고, 실행 순서도 보장하기 때문에 async보다는 defer가 범용적으로 사용할 수 있는 속성으로 정리할 수 있어요.
6

STEP 6

렌더링 엔진은 디바이스 view port 내에서, 렌더 트리의 노드들을 화면의 올바른 곳에 표시하기 위해 정확한 위치와 크기를 계산해요.

  • 이 단계를 레이아웃 단계라고 불러요.
  • 이 작업이 끝나면 렌더링 엔진은 각 요소가 어디에 어떤 크기로 표현되는지 알게 되요.

FINISH

UI BackEnd는 Render Tree의 노드들을 돌며, UI를 그리는 Paint Event를 발생시켜요.

그 다음, 노드들의 레이어를 순서대로 구성하는 Composition단계를 거쳐요. 이 과정은 z-index가 낮은 요소를 먼저 놓고, 높은 요소를 놓는 과정으로 생각해주시면 되요.

Layout단계부터 Composition까지의 과정을 Operation이라고 해요.

리플로우와 리페인트

레이아웃이 변경될 때

리플로우(Reflow)

생성된 DOM 요소의 레이아웃 수치(너비, 높이, 위치 등) 변경 시 영향을 받은 모든 노드의 위치를 다시 계산하는 과정을 의미해요. 레이아웃 단계를 다시 수행하는 것으로 생각할 수 있어요.

아래 버튼을 누르면, 저희가 추천하는 자료를 확인하러 갈 수 있어요!

Learn More
레이아웃이 변경될 때레이아웃이 변경되지 않을 때

리페인트(Repaint)

변경된 요소를 실제로 화면에 그려주는 작업을 리페인트라고 해요.

만약, 노드의 위치를 재계산하는 리플로우가 발생한다면 필연적으로 리페인트가 실행된다고 볼 수 있어요.

아래 버튼을 누르면, 저희가 추천하는 자료를 확인하러 갈 수 있어요!

Learn More

그 외 추천 유튜브 영상

우아한 Tech

[10분 테코톡] ☕️ 체프의 브라우저 렌더링

유튜브 보러가기

코드온

웹 브라우저가 하는 일 : 렌더링 6단계 (현업에 적용하는 CS. 4편)

유튜브 보러가기

아프리카도서관

웹 브라우저의 동작 순서 (6분 순삭)

유튜브 보러가기