브라우저의 동작을 정리한 원문 , 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을 가지고 있다.
다른 엔진일지라도 공통적으로 Rendering
을 하는 주된 flow는 다음과 같다.
이제 각 단계별로 어떤 과정이 일어나는지 보며 과정에서 중요한 점들을 잘 기억해두자.
첫 단계는 각 요소들을 Object Tree구조로 만들어내는 단계다.
브라우저는 서버로부터 응답받은 HTML문서를 읽어내려가며 태그들을 DOM Node
로 변환시킨다.
그 후, CSS파일의 내용도 파싱하면서 CSSOM
을 만들어낸다. <- 여기서 두가지 중요 포인트가 있다 !
1️⃣ CSSOM은 HTML 파싱을 막지 않는다. 또한 완전히 생성되고나서야 랜더링이 된다
HTML파싱이 block되지 않는다.
따라서 link
태그를 만나면 외부 css파일을 받으면서 동시에 DOM tree
를 만든다.2️⃣ 브라우저에 기본적으로 설정된 스타일 값이 합쳐져서 CSSOM에 들어가게 된다
CSSOM을 생성한다는 줄만 알고있었는데 default값이 이때 지정된다는 것은 처음 알게되었다.
❗CheckPoint
💡HTML, CSS의 parsing은 병렬처럼 동작하고 CSS의 작업이 끝나야 랜더링이 된다는 것 !💡 개발을 할 때 아무런 설정없이 css를 default값으로 사용한다면 각 브라우저마다 기본값이 포함되어
우리의 의도대로 UI를 보여줄 수 없을 것💡 브라우저 기본 스타일 초기화 을 통해 각 브라우저의 기본 스타일을 초기화시키거나 고정시킬 수 있다.
🧑💻 FE개발자라면크로스브라우징을 알아두자 !
HTML과 CSS가 어떻게 Parsing되는지에 대한 내용은 여기에 아주 상세히 작성되어있다.
DOM, CSSOM이 모두 생성되었다면 이 둘을 합쳐서 Render Tree를 생성한다.
Render Tree란, 우리가 화면에 볼 수 있는 태그들만을 나타낸 tree구조이다.
Cascading Stylesheet Rules에 의해 우선순위가 계산되어 적용된 CSSOM과,
만들어진 DOM
이 합쳐져서 styled된 태그들을 tree구조로 나타낸다.
❗CheckPoint
👉 화면에 보여질 것들만 Render Tree 에 올라간다. display:none 된 것들은 제외된다는 것을 뜻한다.
💡 반면, visibilty:hidden 은 Render Tree에 포함되어 개발자도구에서 해당 노드를 볼 수 있는 것이다.
최종적으로 그려낼 Render Tree
를 생성했다.
이후 다음 단계는 어느 위치에 Tree의 Node들을 배치할 것인지 계산
하는 과정이다. 이를 Flow
라고 지칭한다.
해당 과정이 어떻게 진행되는지는 gecko 엔진이 화면을 그려내기전 요소들을 배치계산하는 과정을 시각화한 영상을 보면
브라우저가 노드들의 위치를 계산하는 것을 볼 수 있다.
또한, Chrome의 개발자도구를 사용해 Parse시간, layout계산시간을 직접 볼 수 있다.
개발자도구에서 layout을 잡는데 걸린 시간❗CheckPoint
💡 배치에 사용되는 시간은 Chrome 개발자도구를 활용해 직접 확인할 수 있다.💡 이미 한번 계산되었다하더라도 배치계산이 중복해서 일어날 수 있다.
어디에 위치할지 모두 계산이 되었다면 이를 통해 화면에 그려낸다. 이를 Paint
과정이라고 한다.
Rendering 최적화를 위해서 마지막 두 단계. Flow, Paint
가 언제 발생하는지 알고있어야한다.
Paint는 Flow이후 수반되는 과정이므로 Flow를 줄이는 것이 Rendering 최적화의 포인트다.
이전 정리 글에서 참고한 것들을 다시 보자면,
상기에 해당하는 항목들마다 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과 관련해 읽어보면 좋을 것
DomContentLoaded는 DOM Tree가 완성되는 시점 = 외부자원인 img 등을 제외한 HTML 요소를 해석, 구성하는 것
Load는 문서에 있는 모든 컨텐츠(js, img, css 등)이 로드된 상태를 뜻함.
역시 기술 블로그 맛집 세쵸로그!😆
거의 박사학위 논문 수준 아니냐고요!
중간 중간에 링크 걸어준 거 하나하나씩 들어가서 다 봤는데 재밌네요!👍