[CS] 브라우저 동작 원리(Critical Rendering Path)

j.log·2021년 6월 10일
3

CS

목록 보기
6/10


요즈음의 일반적인 스크린은 1초에 화면을 60번 그린다고 합니다. 그러니까 60fps(frame per second)인 것인데, 이 때문에 브라우저 역시 60fps를 유지해야 웹페이지가 매끄럽게 보일 수 있습니다.

하지만 만약 브라우저가 1초에 60프레임을 그려내지 못하게 되면, 웹페이지에서 스크롤을 내린다거나 드래그해서 뭔가를 움직인다거나 할 때 버벅버벅거리는 현상이 생기게 됩니다. (쟁크Jank 현상) 혹은 애초에 페이지 자체가 뜨는 데까지 하세월이 걸릴 수도 있습니다.

⭐ 그렇기 때문에, 최적화(Optimization)가 필요합니다


🙄 그런데, 뭘 최적화해야 하죠??


브라우저가 1초에 60프레임을 그릴 수 있으려면, 1개의 프레임을 그릴 때 약 0.016초(16ms)를 사용해야 합니다. 즉 최대한 한 프레임을 빠르게 그려낼 수 있도록 만들면, 매끈한 웹페이지를 완성할 수 있습니다.



🙄 최적화란?


우리가 일상적으로 접하는 주소창에 url을 입력하고, 엔터키를 치면 브라우저는 해당 서버에 요청(request)을 보내게 됩니다. 서버에서는 응답(response)으로 HTML 데이터를 내려주는데, 이 HTML 데이터를 실제 우리가 보는 화면으로 그리기까지 브라우저는 중요 렌더링 경로(Critical Rendering Path) 거쳐 작업을 진행합니다.

브라우저가 하나의 화면을 그려내는 이 과정중요 렌더링 경로(Critical Rendering Path)라고 부릅니다.

중요 렌더링 경로(Critical Rendering Path)의 각 단계가 최대한 효율적으로 이루어지도록 만드는 것을 보통 최적화라고 부릅니다.



🚩 중요 렌더링 경로(Critical Rendering Path)


  1. [ HTML ] 서버에서 응답으로 받은 HTML 데이터를 파싱한다.
  2. [ DOM Tree ] HTML을 파싱한 결과로 DOM Tree를 만든다. 👉 DOM(Document Object Model) 완성!!
  3. [ CSS ] 파싱하는 중 CSS 파일 링크를 만나면 CSS 파일을 요청해서 받아온다.
  4. [ CSSOM ] CSS 파일을 읽어서 CSSOM(CSS Object Model)을 만든다.
  5. [ Render Tree ] DOM Tree와 CSSOM이 모두 만들어지면 이 둘을 사용해 Render Tree를 만든다.
  6. [ Layout(reflow) ] Render Tree에 있는 각각의 노드들이 화면의 어디에 어떻게 위치할 지를 계산하는 Layout과정을 거친다
  7. [ Paint ] 화면에 실제 픽셀을 Paint한다.



1. 서버에서 응답으로 받은 HTML 데이터를 파싱한다


  <html>
  <head>
      <meta charset="utf-8">
      <link href="./style.css" rel="stylesheet">
  </head>
  <body>
      <p>Hello, <span>web performance</span> students</p>
      <div>
          <img src="./image.png">
      </div>
  </body>
  </html>

브라우저 주소창에 url을 입력하고 엔터키를 치면 브라우저는 해당 서버에 요청을 보내게 됩니다. 요청에 대한 응답으로 위와 같은 HTML문서를 받아오게 되고, 이걸 하나하나 파싱(parsing)하기 시작하면서 브라우저가 데이터를 화면에 그리는 과정이 시작됩니다.
  • 미디어 파일을 만나면 추가로 요청을 보내서 받아옵니다.
  • JavaScript 파일을 만나면 해당 파일을 받아와서 실행할 때까지 파싱이 멈춥니다.



2. HTML에서 DOM Tree로


  • 브라우저는 읽어들인 HTML 바이트 데이터를, 해당 파일에 지정된 인코딩(ex.UTF-8)에 따라 문자열로 바꾸게 됩니다.

  • 바꾼 문자열을 다시 읽어서, HTML표준에 따라 문자열을 토큰Token으로 변환합니다. 이미지에서와 같이 이 과정에서 <html>StartTag: html 로, </html>EndTag: html 로 변환됩니다.

  • 이렇게 만들어진 토큰들을 다시 노드로 바꾸는 과정을 거칩니다.

  • StartTag: html 이 들어왔으면 html노드를 만들고 EndTag:html 을 만나기 전까지 들어오는 토큰들은 html노드의 자식 노드로 넣는 식으로 변환이 이루어지기 때문에, 과정이 끝나면 Tree모양의 DOM(Document Object Model)이 완성되게 됩니다.



3. CSS에서 CSSOM으로


HTML을 파싱하다가 CSS링크를 만나면, CSS파일을 요청해서 받아오게 됩니다.
받아온 CSS파일은 HTML을 파싱한 것과 유사한 과정을 거쳐서 역시 Tree형태의 CSSOM으로 만들어집니다.

  • CSS 파싱은 CSS 특성상 자식 노드들이 부모 노드의 특성을 계속해서 이어받는(cascading) 규칙이 추가된다는 것을 빼고는 HTML파싱과 동일하게 이루어집니다.

  • 이렇게 CSSOM을 구성하는 것이 끝나야, 비로소 이후의 Rendering 과정을 시작할 수 있습니다. (그래서 CSS는 rendering의 blocking 요소라고 합니다.)



4. DOM(Content) + CSSOM(Style) = Render Tree


CSSOM을 모두 만들었으면, DOM과 CSSOM를 합쳐서 Render Tree를 만듭니다.

Render Tree는 DOM Tree에 있는 것들 중에서 화면에 실제로 '보이는' 친구들만으로 이루어집니다.

  • 만약 CSS에서 display: none 으로 설정하였다면, 그 노드(와 그 자식 노드 전부)는 Render Tree에 추가되지 않는 것이죠.

  • 마찬가지로 화면에 보이지 않는 <head> 태그 안의 내용들도 Render Tree에는 추가되지 않습니다.

  • 그래서 위의 이미지의 Render Tree에는 <head> 태그와, display속성이 none인 <p> 태그 하위의 <span> 태그가 사라진 것을 확인할 수 있습니다.



5. Render Object에서 Render Layer로


  • Render Tree에는 사실 여러 가지가 포함되어 있습니다. Render Object Tree, Render Layer Tree 등등을 합쳐서 화면을 그리는 데에 필요한 모-든 정보를 가지고 있는 Render Tree가 완성됩니다. ('등등'에는 Render Style Tree, InlineBox Tree같은 것들도 있습니다.)

  • Render Object Tree가 위에서 말했듯이 DOM Tree의 노드 중에서 화면에 보이는 것들만으로 이루어지는 트리입니다. block, inline, image, text, table같은 요소들이 Render Object가 됩니다. DOM Tree에서 <div>는 Render Object Tree에 Block element로, <span>은 Inline element로 옮겨지는 것이지요.

  • Render Object의 속성에 따라 필요한 경우 Render Layer가 만들어집니다. 그리고 이 Render Layer중에서 GPU에서 처리되는 부분이 있으면 다시 Graphic Layer로 분리됩니다. 대표적으로는 다음과 같은 속성들이 쓰였을 때 Graphic Layer가 만들어지게 됩니다.

    • ranslate3d, preserve-3d 등)이나 perspective 속성이 적용된 경우
    • <video> 또는 <canvas> 요소
    • CSS3 애니메이션함수나 CSS 필터 함수를 사용하는 경우
    • 자식 요소가 레이어로 구성된 경우
    • z-index 값이 낮은 형제 요소가 레이어로 구성된 경우
  • 만약 이런거 저런거 하나도 없이 <div>하나에 width정도 속성만 있다고 하면 레이어는 기본으로 만들어지는 하나만 사용하게 됩니다.



6. Layout(reflow)


화면에 보이는 노드들만을 가지고 있는 Render Tree가 다 만들어지면, 이제 Render Tree에 있는 각각의 노드들이 화면의 어디에 위치할 지를 계산하는 Layout과정을 거칩니다.

  • CSSOM에서 가져온 스타일 정보들로 이미 얘가 어떻게 생겨야 한다는 것은 모두 알고 있지만, 그래서 현재 보이는 뷰포트를 기준으로 실제로 놓으려면 얘가 어디에 가야하는 지는 계산을 또 해야하는 거죠.

  • 여기에서 CSS box model이 쓰이며, position(relative, absolute, fixed..), width, height 등등 틀과 위치에 관련된 부분들이 계산됩니다.

  • 만약 width: 50% 로 되어있는데 브라우저를 리사이즈한다고 하면, 보이는 요소들은 변함이 없으니 Render Tree는 그대로인 상태에서, layout단계만 다시 거쳐 위치를 계산해서 그리게 됩니다.

  • 화면에 보이는 요소 각각이 어디에 어떻게 위치할 지를 정해주는 과정을 Webkit에서는 layout으로, Gecko에서는 reflow로 부르고 있습니다.



7. Paint(repaint)


그리고 드디어 Render Tree의 각 노드들을 실제로 화면에 그리게 됩니다
👉 픽셀화

  • visibility, outline, background-color같이 정말로 눈에 보이는 픽셀들이 여기에서 그려집니다.
  • 만약 Render Layer가 2개 이상이라면 각각의 Layer를 paint한 뒤 하나의 이미지로 Composite하는 과정을 추가로 거친 뒤에 실제로 화면에 그려지게 됩니다.


👀브라우저의 동작원리 흐름 요약

서버로부터 응답받은 HTML 문서를 파싱하여,
HTML은 DOM Tree로 CSS는 CSSOM로 변환하는 작업을 거친다.
그 둘을 결합하여 화면에 유효한 노드만으로 Render Tree를 구성한다.
마지막으로 Render Tree의 각 노드들이 현재 뷰포트 기준으로 화면의 어디에 위치 하는지 계산하는 Layout 과정을 거쳐,
개별 노드를 실제 화면에 Paint 한다.(레스터화)



🖱 출처

profile
jlog

1개의 댓글

comment-user-thumbnail
2023년 4월 3일

공부하는 데 큰 도움이 되었습니다! 좋은 글 감사해요!

답글 달기