[CS] 브라우저 렌더링 과정

miaa·2023년 1월 17일
0

CS | 개발 지식

목록 보기
1/2
post-thumbnail

오늘 우연히 브라우저 렌더링 과정에 대해 이야기를 들었는데.. 도통 무슨 소리인지 이해는 안가지만 알아두면 좋을 것 같아서 정리를 해본다.


브라우저 렌더링?

  • 주소창에 어떤 웹사이트의 주소를 입력하면 해당 사이트가 뜨게 되는데 그 사이에 일어나는 모든 과정들을 뜻한다
  • HTML, CSS, JavaScript 파일을 파싱해서 브라우저에 시각적으로 출력하는 것

브라우저 렌더링 과정 요약

1. 브라우저는 HTML, CSS, JS, 이미지, 폰트 등 리소스를 서버에 요청 하고, 응답으로 받아온다.

2. 브라우저 렌더링 엔진은 받아온 HTML, CSS를 파싱해 DOM, CSSOM을 생성하고, 이들을 결합해 렌더 트리를 생성한다.

3. 브라우저 JS 엔진은 받아온 JS를 파싱해 AST를 생성하고, 바이트코드로 변환해 실행한다.

4. 렌더트리를 기반으로 HTML 요소의 레이아웃(위치, 크기)을 계산한다.

5. 화면에 HTML요소를 페인팅한다.


인터넷 창이 바로바로 뜨는 세상에 익숙해져만 있었지 이런 일렬의 복잡한 과정들이 있을 것이라고 생각도 못했고.. 이제는... 알아야한다는 현실이.. 슬프기까지 하다.

침착하고 계속 알아보자



STEP 1. 요청과 응답

1. 브라우저는 HTML, CSS, JS, 이미지, 폰트 등 리소스를 서버에 요청 하고, 응답으로 받아온다.

  • 우선 화면을 구성할 리소스들이(HTML, CSS, JS..) 대기를 하고 있다

  • 하지만 해당 리소스들은 서버가 가지고 있기 때문에

  • 브라우저는 리소스를 서버에 요청하고 응답을 받아와야한다

아니 근데.. 서버에 요청은 어떻게 하죠?

바로 주.소.창을 통해 요청을 한다

  • 주소창에 URL을 입력하고 엔터키를 누르면

  • URL의 호스트 이름이 DNS(도메인 네임 서비스)를 통해 IP 주소로 변환되고

  • 이 IP 주소를 갖는 서버에게 요청을 보낸다

  • 서버는 기본적으로 index.html을 응답 주도록 설정 되어 있다
    즉, https://www.google.com 를 검색하면 https://www.google.com/index.html 을 요청하는거나 다름이 없단 이야기이다.


예시로 주소창에 https://www.google.com 을 검색하고 아무것도 하지 않았을 때의 모습을 개발자 도구 창으로 확인해보자

  • 그런데 자세히 보면, 여기에는 index.html 뿐만 아니라 요청한 적도 없는 이미지같은 다른 리소스까지 딸려오고 있다.

    • 브라우저 렌더링 엔진은 HTML 파일을 파싱할 때, 위에서 아래로 한 줄 한 줄 파싱한다

    • 그러다가 외부 리소스를 가져오는 태그를 만나면 리소스 파일을 서버로 요청한다

    • 보통 CSS파일은 link, Javascript파일은 script, 이미지는 img로 가져오는데, 이런 태그들을 만나 리소스들을 서버에서 받아오는 것이다

  • 위에서도 이처럼 index.html 문서에 있던 요청들에 대한 응답들까지 계속 받아오고 있는 것을 확인할 수 있다



STEP 2-1. HTML 파싱, DOM생성

2. 브라우저 렌더링 엔진은 받아온 HTML, CSS를 파싱해 DOM, CSSOM을 생성하고, 이들을 결합해 렌더 트리를 생성한다.

  • 응답으로 받아온 HTML 문서는 오직 텍스트로만 이루어져있다

  • 이 텍스트들이 대체 어떻게 우리가 보는 화면이 되는걸까?

  • 일단은 이 문서를 브라우저가 이해할 수 있는 형태로 바꾸는 작업이 필요한데, 여기서 말하는 형태가 바로 DOM 구조 이다.

  1. 바이트(Bytes)
    : 서버는 브라우저에게 2진수 형태의 HTML 문서를 응답으로 준다.

  2. 문자열(Characters)
    : 문서는 < meta >의 charset 속성에 지정된 방식으로 문자열로 인코딩 된다.(ex. UTF-8) 서버는 이 인코딩 방식은 응답 헤더에 담아준다.

  3. 토큰(Tokens)
    : 문자열 형태의 HTML문서를 '토큰'단위로 분해한다. (문법적 의미를 갖는 코드의 최소 단위)

  4. 노드(Nodes)
    : 각 토큰을 객체로 변환해, 노드를 생성한다. (DOM을 구성하는 기본 요소)

  5. DOM
    : HTML문서의 요소들의 중첩관계를 기반으로 노드들을 트리 구조로 구성한다. 이 트리를 DOM이라고 한다.

DOM?

  • Document Object Model의 줄임말인데, 우리말로는 문서 객체 모델이라 할 수 있다.
  • 말 그래도 문서를 → 객체로 바꾼 모델이다.

  • 브라우저는 Javascript 언어만 알아들어서 Javascript는 HTML의 태그나 속성들을 바로 다룰 수 없기 때문에, 다룰 수 있는 형태인 '객체' 로 바꿔주어야 한다.

  • 그래야 브라우저가 HTML 문서를 이해할 수 있게 되는 것이다.

위와 같은 과정을 거쳐서 HTML 문서가 파싱되고, DOM 이라는 결과물을 생성하게 된다


STEP 2-2. CSS 파싱, CSSOM 생성

  • html 파일을 파싱하다가 < link >, < style > 태그를 만나면 파싱을 잠시 멈추고 리소스 파일을 서버로 요청한다고 했었다.

  • 이 태그들은 CSS 파일을 가져올 때 보통 쓰는데, 이렇게 가져온 CSS 파일도 HTML과 마찬가지로 파싱을 한다

  • 서버에서 받아온 2진수 파일을 문자열로 인코딩하고, 토큰 단위로 나누고, 노드를 생성하고, 트리를 만들고.. 이렇게 파싱해 만든 트리는 CSSOM 이라고 한다.

  • CSSOM은 CSS 문서를 객체 모델로 바꾼 것이다

  • CSSOM을 생성하고 나면, HTML파일은 다시 본론으로 돌아가 파싱을 멈췄던 부분부터 다시 파싱을 시작해 DOM을 마저 생성한다

  • CSS의 속성은 상속이 되기 때문에, 이를 반영한다는 점이 조금 다른 점이다


DOM 과 CSSOM 은 굉장히 비슷하지만 사실 서로 다른 속성을 가진 독립적인 트리들이다

HTML은 구조를 CSS는 디자인을 담당하기 때문에 얘네들을 합쳐주는 작업이 또 필요하다


STEP 2-3. 렌더 트리 생성

  • 이름처럼 렌더링을 목적으로 만드는 트리

  • 렌더링은 브라우저가 이제 진짜로 사용자에게 보여주기 위한 화면을 그리는 과정이기 때문에, 보이지 않을 요소들은 이 트리에 포함하지 않는다

  • 위의 그림처럼 DOM, CSSOM 에 있던 속성들이 합쳐져 렌더트리를 구성하는 것을 확인할 수 있다

  • 그런데 화면에 보여주는데 쓰인다고 했지만, 렌더트리는 아직까지도 텍스트로 구성된 객체로밖에 보이지 않는다

  • 실제로 우리가 보는 페이지를 만들기 위해서는 '페인팅'이라는 작업을 거쳐야 한다

  • 페인팅 작업은 렌더트리의 노드들이 가지고 있는 속성들을 바탕으로 이루어지는데, 이 작업은 잠시 후에 다시 자세히 알아보도록 하고 우선은 Javascript 파일은 어떻게 해석이 되는지부터 잠시 살펴보자.


STEP 3. Javascript 파싱

3. 브라우저 JS 엔진은 받아온 JS를 파싱해 AST를 생성하고, 바이트코드로 변환해 실행한다.

  • 렌더링 엔진은 HTML 파일을 한줄씩 파싱하며 DOM을 생성하다가 Javascript 코드들 불러오는 < script > 태그를 만날 때도 파싱을 잠시 멈춘다

  • 그리고나서 src 속성에 적혀있는 파일을 서버에 요청해 받아온다

  • 이렇게 받아온 js파일도 마찬가지로 파싱을 해야하는데, 이 파싱은 브라우저 렌더링 엔진이 직접 하지 않고, Javascript 엔진이 담당하게 된다

이 때 렌더링 엔진은 JS엔진에게 제어권을 아예 넘겨주기 때문에, HTML 파싱을 멈췄다가 js파싱이 다되면 다시 제어권을 돌려받아 파싱을 다시 시작하는 것이다

  • JS엔진은 js파일의 코드를 파싱해서 컴퓨터가 이해할 수 있는 기계어로 변환하고 실행한다

  • 좀 더 구체적으로 살펴보면, 먼저 단순한 텍스트 문자열인 코드를 토큰 단위로 분해한다

  • 이렇게 분해된 토큰에 문법적인 의미와 구조가 더해져, AST(추상 구문 트리) 라는 트리가 완성된다

  • 구체적인 속성은 다르지만, 이전에 봤던 과정들과 비슷해 보인다. 위 그림에서 맨 왼쪽의 코드가 바로 다음의 트리 구조로 바뀌는 부분이 여기까지의 내용에 해당한다


STEP 4. 레이아웃(리플로우)

4. 렌더트리를 기반으로 HTML 요소의 레이아웃(위치, 크기)을 계산한다.

  • 2-3에서 만들었던 렌더트리가 여기서 사용되니 다시 떠올려야 한다

  • 렌더트리에는 요소들의 위치나 크기와 관련된 정보들이 들어있었다

  • 하지만 이 정보들은 각 요소들에 대한 정보일 뿐, 전체 화면에서 정확히 어디에 위치할 것인지에 대해서는 아직 알지 못한다

이런 계산을 하는 단계가 레이아웃 단계이다

  • 브라우저는 각 요소들이 전체 화면에서 어디에, 어떤 크기로 배치되어야 할 지 파악하기 위해

  • 렌더트리의 맨 윗부분부터 아래로 내려가며 계산을 진행한다

  • 이때 모든 값들은 절대적인 단위인 px값으로 변환된다

ex ) 우리가 < div >요소 하나만 띄우도록 코드를 작성했고, width를 50%로 지정해두었다면, 이 값은 전체 화면 크기(viewport)의 절반 크기로 계산되고, 절대적인 값인 px 단위로 변환되는 식이다.


STEP 5. 페인팅

5. 화면에 HTML요소를 페인팅한다.

이제 위치에 대한 계산도 마쳤으니, 정말로 화면에 보여줄 차례이다

  • 브라우저 화면은 픽셀이라고 하는 정말 작은 점들로 이루어져 있다

  • 각각 정보를 가진 픽셀들이 모여 하나의 이미지, 화면을 구성하는 것

  • 따라서 화면에 색상을 입히고, 어떤 요소를 보여주기 위해서는 이 픽셀에 대한 정보가 있어야 한다

페인팅은 이러한 픽셀들을 채워나가는 과정이다

따라서 이 과정을 마지막으로 우리는 단순한 텍스트에 불과했던 파일 내용들을 이미지화된 모습으로 브라우저 화면을 통해 볼 수 있게되는 것이다.


잠깐만!

만약 사용자가 브라우저 화면을 늘리거나 줄이는 등 크기를 조절하거나, 어떤 버튼을 눌러 화면에 요소가 추가되거나 삭제되는 경우가 생기면 당연히 화면에 있던 요소들의 위치나 크기 등이 바뀌는 일이 생기게 될 것이다

이쯤 돼서 알아야할 용어들이 있다

리플로우 : 레이아웃 계산을 다시 하는 것

리페인트 : 새로운 렌더트리를 바탕으로 다시 페인팅을 하는 것

  • 굉장히 당연하게 여겨지지만, 이렇게 화면에 나타나는 모습을 바꾸기 위해서는 모든 요소들의 위치와 크기를 다시 계산하고, 다시 그려서 보여주어야 한다

  • 이렇게 어떤 인터랙션으로 인해 앞서 보았던 레이아웃, 페인팅 과정을 반복하는 것을 리플로우, 리페인트 라고 한다

  • 위의 코드가 Javascript를 통해 DOM을 조작하는 코드이다

  • DOM은 단순히 HTML 파일의 정보만 담고있게 아니라, 이렇게 Javascript를 통해 요소들을 동적으로 조작할 수 있도록 DOM API라는 것을 제공한다

  • CSS도 마찬가지로 이런식으로 조작이 가능하다

  • 이렇게 Javascript 조작으로 변경이 일어나면, DOM트리를 다시 구성하는 것으로 시작해 CSSOM와 합쳐져 새 렌더 트리를 생성한다

  • 그리고 레이아웃과 페인트 과정을 또다시 거쳐서 화면에 보여진다.

  • DOM 조작은 리플로우, 리페인팅이 일어나는 대표적인 예시라고 할 수 있다

물론 레이아웃과 페인트는 별개의 작업이기 때문에, 하나씩만 발생할 수도 있고, 둘다 발생할 수도 있다

위치나 크기에 대한 변경만 있다면 레이아웃 작업만 다시하면 되고, 요소의 색상이나 보이는지 여부 같은 스타일에 대한 사항에 대한 변경만 있다면 페인팅 작업만 다시하면 된다

(컴퓨터 : 죽여줘...)


한번 더 정리 해보자

1. 브라우저는 HTML, CSS, JS, 이미지, 폰트 등 리소스를 서버에 요청 하고, 응답으로 받아온다.

2. 브라우저 렌더링 엔진은 받아온 HTML, CSS를 파싱해 DOM, CSSOM을 생성하고, 이들을 결합해 렌더 트리를 생성한다.

3. 브라우저 JS 엔진은 받아온 JS를 파싱해 AST를 생성하고, 바이트코드로 변환해 실행한다.

4. 렌더트리를 기반으로 HTML 요소의 레이아웃(위치, 크기)을 계산한다.

5. 화면에 HTML요소를 페인팅한다.


💙 브라우저의 랜더링 엔진은 HTML, CSS파일로 DOM과 CSSOM을 생성한다

💙 이 둘은 렌더트리로 결합되고

💙 이 렌더트리는 요소들의 크기, 위치를 계산하는 레이아웃 작업과 픽셀을 통해

💙 화면에 실제로 그리는 작업인 페인팅 단계에 활용된다

💙 여기까지의 과정을 마치면 사용자는 웹페이지를 볼 수 있게 된다.


추가로, DOM은 DOM API를 제공하기 때문에, Javascript로 이미 생성된 DOM을 조작할 수 있다는 것도 소개했다

이런 조작으로 인해 요소들에 변경 사항이 생기면, 앞의 과정을 다시 수행하게 된다

레이아웃단계를 다시 반복하는걸 리플로우, 페인팅단계를 다시 반복하는걸 리페인팅이라 한다



먼저 이 글을 정리해주신 분들께 무한한 감사 올립니다.....

참고 사이트

profile
엉금엉금

0개의 댓글