1탄_브라우저 작동 원리_랜더링과정

수박·2021년 8월 13일
5

browser

목록 보기
2/4
post-thumbnail

브라우저의 동작을 정리한 원문 , d2 포스팅를 참고한 포스팅입니다.
Rendering Engine이 UI를 그려내기까지의 과정을 다루고 있으며,
이전_랜더링과정을 정리해놓은 글 에서 추가적인 사항을 보완해서 작성했습니다.



브라우저 구성요소

브라우저는 크게 다음 요소들로 구성되어있다.

이 중 아래서 계속 다룰 내용은 Rendering Engine에 대한 내용이다.

user Interface : 뒤로가기, 북마크등을 나타냄

rendering engine: 서버로부터 응답받은 콘텐츠가 HTML일 때 HTML, CSS를 parsing, 해당 콘텐츠를 화면에 그려냄 - 브라우저마다 다른 엔진을 사용 (크롬 : blink, 파이어폭스: gecko)

Browser engine : User interface와 rendering engine 사이 동작을 제어

Networking: 브라우저에서 발생하는 요청, 응답을 할 때 사용되는 HTTP, FTP등과 함께 사용할 URL을 처리

JS Interpreter: JS코드를 해석 및 실행

UI Backend : select, input, check box와 같은 widgets을 그리는데에 도움  참고

Data storage: session, cookies, local Storage 등을 저장

! Rendering engine웹 문서를 UI화하기까지의 과정을 살펴보자


Rendering engine 동작과정 (feat. 중요 포인트)

브라우저마다 화면을 그려내는 다른 rendering engine을 가지고 있다.

다른 엔진일지라도 공통적으로 Rendering 을 하는 주된 flow는 다음과 같다.

  1. HTML, style을 parsing한다. 이후  DOM tree, CSSOM tree를 생성한다, 
  2. DOM + CSSOM을 합쳐 Render tree를 생성한다.
  3. Render tree의 node들을 어디에 위치시킬지 계산한다.
  4. Render tree를 그린다.

이제 각 단계별로 어떤 과정이 일어나는지 보며 과정에서 중요한 점들을 잘 기억해두자.


1. HTML, CSS 파싱 후  *OM생성

첫 단계는 각 요소들을 Object Tree구조로 만들어내는 단계다.

브라우저는 서버로부터 응답받은 HTML문서를 읽어내려가며 태그들을 DOM Node로 변환시킨다.

그 후, CSS파일의 내용도 파싱하면서 CSSOM 을 만들어낸다. <- 여기서 두가지 중요 포인트가 있다 !


1️⃣ CSSOM은 HTML 파싱을 막지 않는다. 또한 완전히 생성되고나서야 랜더링이 된다

  • CSS자체로는 DOM의 구조를 변경시키지 않기에 HTML파싱이 block되지 않는다. 따라서 link 태그를 만나면 외부 css파일을 받으면서 동시에 DOM tree 를 만든다.
  • CSS가 채 load되지 않았다면 스타일링이 적용되지 않은 화면이 보여질 것이다.

2️⃣ 브라우저에 기본적으로 설정된 스타일 값이 합쳐져서 CSSOM에 들어가게 된다

  • 브라우저마다 기본적으로 padding margin, ...etc값이 기본적으로 지정되어있다.
  • 개발자가 아무런 스타일을 주지 않았다면 해당 값으로 CSSOM을 만들어놓아버린다.
  • react에서 CSS를 reset하거나 normalize하는 이유다.

CSSOM을 생성한다는 줄만 알고있었는데 default값이 이때 지정된다는 것은 처음 알게되었다.

CheckPoint

💡HTML, CSS의 parsing은 병렬처럼 동작하고 CSS의 작업이 끝나야 랜더링이 된다는 것 !

💡 개발을 할 때 아무런 설정없이 css를 default값으로 사용한다면 각 브라우저마다 기본값이 포함되어
우리의 의도대로 UI를 보여줄 수 없을 것

💡 브라우저 기본 스타일 초기화 을 통해 각 브라우저의 기본 스타일을 초기화시키거나 고정시킬 수 있다.

🧑‍💻 FE개발자라면크로스브라우징을 알아두자 !

      HTML과 CSS가 어떻게 Parsing되는지에 대한 내용은 여기에 아주 상세히 작성되어있다.

DOM, CSSOM이 모두 생성되었다면 이 둘을 합쳐서 Render Tree를 생성한다.



2. Render Tree 생성

Render Tree란, 우리가 화면에 볼 수 있는 태그들만을 나타낸 tree구조이다.

Cascading Stylesheet Rules에 의해 우선순위가 계산되어 적용된 CSSOM과, 만들어진 DOM이 합쳐져서 styled된 태그들을 tree구조로 나타낸다.

❗CheckPoint

👉 화면에 보여질 것들만 Render Tree 에 올라간다. display:none 된 것들은 제외된다는 것을 뜻한다.

💡 반면, visibilty:hidden 은 Render Tree에 포함되어 개발자도구에서 해당 노드를 볼 수 있는 것이다.



3. Render Tree 배치 (aka.flow)

최종적으로 그려낼 Render Tree 를 생성했다.

이후 다음 단계는 어느 위치에 Tree의 Node들을 배치할 것인지 계산 하는 과정이다. 이를 Flow 라고 지칭한다.

해당 과정이 어떻게 진행되는지는 gecko 엔진이 화면을 그려내기전 요소들을 배치계산하는 과정을 시각화한 영상을 보면

브라우저가 노드들의 위치를 계산하는 것을 볼 수 있다.

또한, Chrome의 개발자도구를 사용해 Parse시간, layout계산시간을 직접 볼 수 있다.

개발자도구에서 layout을 잡는데 걸린 시간

CheckPoint

💡 배치에 사용되는 시간은 Chrome 개발자도구를 활용해 직접 확인할 수 있다.

💡 이미 한번 계산되었다하더라도 배치계산이 중복해서 일어날 수 있다.



4. Render tree 그리기 (aka.paint)

어디에 위치할지 모두 계산이 되었다면 이를 통해 화면에 그려낸다. 이를 Paint 과정이라고 한다.



🧐 Rendering에서 우리가 염두에 둘 것

Rendering 최적화를 위해서 마지막 두 단계. Flow, Paint 가 언제 발생하는지 알고있어야한다.

Paint는 Flow이후 수반되는 과정이므로 Flow를 줄이는 것이 Rendering 최적화의 포인트다.

이전 정리 글에서 참고한 것들을 다시 보자면,

  • 페이지 초기 렌더링 시(최초 Layout 과정)
  • 윈도우 리사이징 시 (Viewport 크기 변경시)
  • 노드 추가 또는 제거
  • 요소의 위치, 크기 변경 (left, top, margin, padding, border, width, height, 등..)
  • 폰트 변경과(텍스트 내용) 이미지 크기 변경(크기가 다른 이미지로 변경 시)

상기에 해당하는 항목들마다 flow- paint과정이 일어난다.

위에서 flow에 약 6.54ms가 소요되었다는 것을 볼 때 규모가 있는 사이트에선 더 걸릴 것이다.

0.1초마다 1px씩 이동되는 요소가 있을 경우 0.1초마다 flow계산 시간이 소요된다면 무시하지 못할 숫자다.

이런 요소가 한 화면에 10개 20개씩 있다면 뚝뚝 끊기는 등 원하는 UI를 보여줄 수 없을 것이다.

Reflow, Repaint를 피하는 속성들을 참고해 더 적절한 방식으로 스타일링 하는 것이 중요하다.
애니메이션에서 불필요한 속성 하나가 랜더링 성능에 끼치는 영향을 읽으면 체감이 확 된다 !



여기까지 rendering engine이 웹문서를 어떻게 화면에 그려내는지에 대한 과정이었다.

정리를 통해 각 과정이 어떻게 진행되는지 이해했고 reset-css라이브러리를 사용하는 이유와 rendering 최적화를 해야하는 이유에 대해 알 수 있었다.




다음은, 외부 CSS, Script를 HTML내에서 불러올 때 어느 위치에 삽입해야할지에 대해 보자.

script가 보통 body 하단에 위치해있는데 왜 그럴까 ?

💡 중요한 스크립트와 스타일시트 진행 순서

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="utf-8" />
  <title>농담곰</title>
  <link rel="stylesheet" type="text/css" href="style.css">
  <script src="script.js"></script>
</head>

<body>
  <img src="/imgaes/농담곰.png"/>
  <div id="root"></div>
  <script src="권장되는_script.js"></script>
</body>
</html>

브라우저가 상단의 HTML을 서버로부터 응답 받았을 때 Rendering engine은 HTML을 파싱하기 시작한다.

외부 css를 load하는 것의 위치는 크게 중요하지 않으나 script의 위치는 매우 중요하다.

script를 만나면 브라우저의 JS interpreter가 해석, 수행하는 동안 HTML 해석이 중단된다.

따라서 script를 최상단에 두게되면 그만큼 사용자에게 보여주는 UI rendering은 늦춰지게 되므로 UX가 떨어지게된다.

그래서 script는 제일 하단에 위치시키는 것이 권장된다.

block을 피하는 방법도 있는데, script태그에 async속성을 추가하는 것이다.

반대로 defer속성은 HTML 분석 완료 이후, script를 실행하도록 지시할 수 있다.


<script> async src\="jquery.js"\></script\>

<script> defer src\="jquery.js"\></script\>

script를 가져오고 실행하기 위해서 block하지만 async 속성을 사용해 일시 중지를 막을 수 있다.

언제 이 속성을 쓸 것인지에 대한 자세한 내용은 https://webclub.tistory.com/630 을 참고해보자.




🧑‍💻 정리

브라우저가 서버에 요청을 보내어 서버가 페이지 자원을 응답함

브라우저의 랜더링엔진은 서버가 응답한 HTML문서를 HTML, CSS로 파싱하기 시작함

파싱되면서 각각의 OM-트리구조로 생성함

DOM, CSSOM을 합쳐 Render Tree를 생성 후 각 노드들을 어디에 위치시킬지 계산함

계산된 내용을 바탕으로 실제 화면에 그려냄

계산을 줄이는 것이 랜더링최적화의 포인트- 계산을 피하는 속성들을 사용, 참고하기

script태그를 만나면 파싱이 blocking되기에 그만큼 ui에 보여지는 시간이 지연되어

script태그를 하단에 위치시킬 것이 권장된다.

그리고 async, defer 속성을 통해 script실행시점을 설정할 수 있다.



DOM과 관련해 읽어보면 좋을 것

DOM과 관련된 이벤트

DomContentLoaded는 DOM Tree가 완성되는 시점 = 외부자원인 img 등을 제외한 HTML 요소를 해석, 구성하는 것

Load는 문서에 있는 모든 컨텐츠(js, img, css 등)이 로드된 상태를 뜻함.



참고 링크

3개의 댓글

comment-user-thumbnail
2021년 8월 13일

역시 기술 블로그 맛집 세쵸로그!😆
거의 박사학위 논문 수준 아니냐고요!
중간 중간에 링크 걸어준 거 하나하나씩 들어가서 다 봤는데 재밌네요!👍

1개의 답글
comment-user-thumbnail
2021년 8월 14일

우와..저 브라우저 작동 원리 공부하고 secho님꺼 보는데 모르거나 헷갈린 부분들이 여기에서 알고 가요. HTML, CSS의 parsing은 병렬처럼 동작한다거나 그런 디테일한 부분들 말이죠! 🤓 정말 같이 공부하듯이 구성한게 매력인 것 같습니다.

답글 달기