브라우저 렌더링
우리는 매일 같이 크롬, 사파리 등의 다양한 브라우저를 통해 편리하게 웹사이트를 접속하고, 사용하고 있다. 어떤 방식으로 브라우저에서 웹 페이지가 렌더링 되는지, 그 과정을 정리해보자 한다.
브라우저란 무엇일까?
브라우저의 주요 기능 은 사용자가 선택한 자원을 서버에 요청하고 브라우저에 표시하는 것이다.
먼저 브라우저는 서버에서 받아온 HTML 문서를 W3C(World Wide Web Consortium)에서 정한 HTML과 CSS 명세에 따라 명세를 따라 HTML를 해석한다.
브라우저의 구조
브라우저는 크게 화면을 조정하는 영역과 데이터를 조작하는 영역으로 구분
- 사용자 인터페이스 : 주소 표시줄, 이전/다음 버튼, 북마크 메뉴 등. 요청한 페이지를 보여주는 창을 제외한 나머지 모든 부분
- 브라우저 엔진 : 사용자 인터페이스가 렌더링 엔진에 쿼리를 전달할 수 있게 조작을 담당
- 렌더링 엔진 : 요청한 콘텐츠를 표시. html과 css 문서를 파싱 / 해석하여 화면에 표현
- 통신 : HTTP 요청을 할 수 있으며, 네트워크 호출. 플랫폼 독릭접인 인터페이스이고 각 플랫폼 하부에서 실행됨.
- UI Backend: 콤보 박스와 창 같은 기본적인 장치를 그림. 플랫폼에서 명시하지 않은 일반적인 인터페이스로서, OS 사용자 인터페이스 체계를 사용.
- Javascript 해석기 : Javascript 코드를 해석하고 실행
- 자료 저장소 : Cookie, Local storage등 모든 자료를 저장하는 영역
대표적인 렌더링 엔진으로 파이어폭스에서 사용하는 게코(Gecko)와, 사파이와 크롬에서 사용하는 웹킷(Webkit) 엔진이 있지만, 렌더링 방식은 크게 다르지 않다.
동작 과정
렌더링 엔진은 통신으로부터 요청한 문서의 내용을 얻는 것으로 시작하는데 문서의 내용은 보통 8KB 단위로 전송된다.
(TTFB: Time to First Byte (첫 번째 바이트까지의 시간) - 링크를 클릭한 후 처음으로 들어오는 콘텐츠 비트 사이의 시간을 의미)
렌더링 엔진은 HTML 문서를 파싱하고 "콘텐츠 트리" 내부에서 태그를 DOM 노드로 변환한다. 그다음 외부 CSS 파일과 함께 포함된 스타일 요소도 파싱한다. 스타일 정보와 HTML 표시 규칙은 "렌더 트리"라고 부르는 또 다른 트리를 생성
렌더 트리는 색상 또는 면적과 같은 시각적 속성이 있는 사각형을 포함하고 있는데 정해진 순서대로 화면에 표시된다.
렌더 트리 생성이 끝나면 배치가 시작되는데 이것은 각 노드가 화면의 정확한 위치에 표시되는 것을 의미한다.
다음은 UI 백엔드에서 렌더 트리의 각 노드를 가로지르며 형상을 만들어 내는 그리기 과정이다.
렌더링 엔진은 좀 더 나은 사용자 경험을 위해 가능하면 빠르게 내용을 표시하는데 모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 시작한다. 네트워크로부터 나머지 내용이 전송되기를 기다리는 동시에 받은 내용의 일부를 먼저 화면에 표시하는 것이다.
DOM 트리 구축
HTML문서를 받아오면, 렌더링 엔진이 HTML파서를 이용해 파싱을 시작한다. 그리고 파싱이 완료되면 문서 구조는 "파싱 트리"로 생성된다. 파싱하는 문서는 어휘 분석과 구문 분석으로 해석되며, 어휘 분석은 자료의 유요한 토큰(의미 없는 문자와 공백)을 분해하고, 구문 규칙으로 문서 구조를 분석한다. 어휘 분석으로 html 태그를 토큰으로 파싱한다. 해당 과정을 통해 파싱 트리가 만들어진다. 파싱 트리를 기반으로, DOM 요소와 속성 노드를 가지는 DOM 트리를 생성한다.
변환
파싱트리는 최종 결과물이 아니다. 파싱은 보통 문서를 다른 양식으로 변환하는데 컴파일이 하나의 예가 된다. 소스 코드를 기계 코드로 만드는 컴파일러는 파싱 트리 생성 후 이를 기계 코드 문서로 변환한다.
HTML 파서는 HTML 마크업을 파싱 트리로 변환한다.
파싱 트리를 기반으로, DOM 요소와 속성 노드를 가지는 DOM 트리를 생성한다.
<!DOCTYPE html> <html> <head> <title>Document</title> </head> <body> <p>Hollow World!</p> <div><img src="" alt="" /></div> </body> </html>
태그 중첩이 너무 깊을 때 최대 20개의 중첩만 허용하고 나머지는 무시한다.
트리 생성이 끝나면 브라우저는 화면을 그리기 시작하며, 문서는 ready 상태가 되고 load 이벤트가 발생된다. DOM 로드가 완료되면 Javascript를 다운로드하기 시작하며, Javascript도 파싱한다. 하지만 CSS 파서는 DOM Tree에 영향을 주지 않기 때문에 문서를 파싱하는 동시에 파싱을 진행하며, CSS는 CSSOM 트리를 생성한다.
HTML 마크업 내에 직접(inline) 스타일을 선언할 수도 있지만, head 태그에 외부(external) css 파일을 참조하거나, head 태그에 style 태그(internal)를 정의할 수 있다. HTML과 마찬가지로 외부(external) css 파일에 정의된 스타일과 style 태그에 작성된 스타일을 브라우저가 이해하고 처리할 수 있는 형식으로 변환해야 한다.
DOM 트리를 생성하는 과정과 동일한 과정으로 CSSOM 트리를 생성한다.

이런 과정을 거쳐서 마지막으로 CSSOM(CSS Object Model)이라는 트리 구조가 생성된다.
CSS는 위에 Script는 아래에?
웹브라우저의 렌더링 순서를 이해하면 이해가 가는 말이다.
문서를 파싱해서 DOM Tree를 만들어도 스타일 규칙이 없으면 렌더링 할 수가 없다.
즉, 최대한 빨리 스타일 규칙을 알아야 렌더링 트리가 완전히 만들어지므로 스타일시트 파일을 모두 다운로드시키기 위해 <head></head> 태그 사이에 놓는 것이다. (인터프리터에서 html파일 위에서 아래로 읽음)
자바스크립트는 왜 아래에 놓아야 성능이 좋아질까?
자바스크립트는 DOM객체를 이용해서 컴포넌트들을 조작하는데 <head></head>태그 사이처럼 상단에 놓게 되면 HTML파서가 파싱을 멈추고 스크립트 파일을 읽기 때문이다.
파싱을 멈추고 읽기 때문에 위에서 스크립트 파일이 많거나 파일이 크면 읽는 시간이 오래 걸려 사용자 입장에서 웹페이지가 느리게 보이게 되므로 느리다고 느낄 수 있다.
심지어 잘 못 코딩했을 경우 HTML 파싱보다 자바스크립트 파일이 먼저 실행돼서 적용이 안 되는 모습도 볼 수 있다.
렌더 트리 구축
DOM 트리가 구축이 되어가는 동안 브라우저는 DOM 트리를 기반으로 렌더 트리를 생성한다. 문서를 시각적인 구성 요소로 만들어주는 역할을 한다. 1:1로 대응되지는 않는다. 대표적인 예로 <head>나 display:none, hidden 은 렌더 트리에 포함되지 않습니다.
스타일은 브라우저에서 제공하는 기본 스타일 시트를 따라간다. 적용된 스타일 속성에 따라 렌더 트리를 구축한다.
다음은 기기의 뷰포트 내에서 노드들의 정확한 위치와 크기를 계산하는 과정이 진행된다. 이 단계가 레이아웃 단계이며, 리플로우라고도 한다.
페이지에서 각 객체의 정확한 크기와 위치를 파악하기 위해 브라우저는 렌더링 트리의 루트부터 시작하여 렌더링 트리를 순회한다.
이 작업이 끝나면, 이제 렌더링 엔진은 각 요소가 어디에 어떤 크기로 표현될지 알게 된다. 렌더링 엔진은 페인트 이벤트를 발생시켜 렌더링 트리를 화면에 그리고, 이 과정을 페인팅 또는 래스터화라고 한다.
모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 진행한다.
웹페이지에 접속했을 때, 페이지가 한꺼번에 뜨지 않고 점점 화면에 그려지는 것이 이 때문이다.
리플로우(Reflow), 리페인트(Repaint)
사용자가 웹 페이지에 처음 접속을 하면, 렌더링 과정을 거쳐서 화면에 모든 요소가 그려지게 된다. 이후 사용자는 다양한 액션을 수행하게 되고, 여기서 발생되는 이벤트로 인해서 새로운 HTML 요소가 추가되거나, 기존 요소의 스타일이 바뀌거나 하는 변경이 일어나게 된다.
이런 변경을 통해 영향을 받게 되는 모든 노드에 대해서 렌더링 트리 생성과 레이아웃 과정을 다시 수행하게 된다. 이러한 과정을 리플로우(Reflow)라고 한다.
리플로우는 단지 변경사항을 반영하기 위해서 렌더링 트리를 생성하고 레이아웃 과정을 다시 수행하는 것이고, 실제 이 결과를 화면에 그려지기 위해서는 다시 페인팅 단계를 수행해야 한다. 이 과정을 리페인트(Repaint)라고 한다.
기존 요소에 변경 사항이 생겼다고 해서 항상 리플로우(Reflow)-리페인트(Repaint)가 일어나는 것은 아니고, 레이아웃에 영향이 미치지 않는 단순한 색상 변경 같은 변경사항은 리플로우(Reflow) 수행 없이 바로 리페인트(Repaint)만 수행하게 된다.
(리플로우가 일어나면 반드시 리페인트가 일어난다)
리플로우(Reflow)가 일어나는 대표적인 속성들
position, width, height, margin, padding, border, border-width, font-size, font-weight, line-height, text-align, overflow
리페인트(Repaint)만 일어나는 대표적인 속성들
background, color, text-decoration, border-style, border-radius
참고
- https://d2.naver.com/helloworld/59361
- https://pks2974.medium.com/website%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%B3%B4%EC%97%AC%EC%A3%BC%EA%B2%8C-%EB%90%A0%EA%B9%8C-f1193c844480
- https://medium.com/%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%9D%98%ED%92%88%EA%B2%A9/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95-5c01c4158ce
- https://developers.google.com/web/updates/2019/02/rendering-on-the-web?hl=ko
'IT' 카테고리의 다른 글
[Error] Parsing error: No Babel config file detected for _ (0) | 2022.04.13 |
---|---|
리액트(React.js) vs 뷰(Vue.js) (4) | 2022.01.26 |
[GIT] .gitignore가 작동하지 않을 때 대처 방법 (0) | 2021.10.31 |
[AWS] MAC terminal로 ssh키 접속 [Permission Error] (0) | 2021.09.16 |
VScode - React styled-components 속성 색상을 구분하자(extenstion - vscode-styled-componenets) (0) | 2021.08.07 |
댓글