브라우저가 사용자에게 보여지는 과정을 정리해보자.
이 정리의 목적은 크게 두가지다.
첫째, 프론트엔드 개발자로서 취업하려면 브라우저 렌더링 원리는 기술면접에서 반드시 나올 필수 질문이다.
그렇다면, 어째서 이런 질문을 하는걸까.
그게 바로 둘째 목적인데, 브라우저 렌더링 원리를 알면 코딩에서 얻을 수 있는 이점이 많기 때문이다.
이점 중 하나는, 코딩을 할때 발생하는 버그 중 브라우저 렌더링 원리와 관련된 문제를 이해할 수 있게 된다.
(애니메이션을 만들 때 display:none은 구현이 안되고, visibility:hidden은 구현이 되는 이유가 하나의 예시다.)
다른 하나는, 브라우저에서 페이지가 더 빨리 구현되고 더 부드러워지는 것, 즉 '브라우저 최적화'를 위해서다.
렌더링 원리를 알면 그에 적절한 코드를 사용하여 브라우저를 훨씬 더 빠르게 할 수 있고 사용자가 지루해하지 않도록 할 수 있다.
1. 웹 표준, 브라우저
세상에는 다양한 브라우저가 있다. 그렇다면 개발자는 각 브라우저가 html,css 등의 언어를 어떻게 구현하는지 하나하나 별개로 배워야 하는가?
그렇지않다.
그 이유를 하나씩 보자.
브라우저가 페이지를 구현하는 자원인 HTML,CSS로 웹 표준화 기구인 W3C(World Wide Web Consortium)의 표준을 준수한다. 또한, javascript는 ECMA international에서 관리한다. 이러한 웹 표준 덕분에 개발자가 짠 코드는 대개 모든 브라우저에서 페이지 상에 비슷하게 구현될 수 있다(물론 브라우저마다 지원하는 기능이 조금씩 차이는 존재한다. 특히 IE는 안되는 기능이 더 있을 수 있다.)
하지만, 어디까지나 최종 결과물이 비슷해보이는거지 그 과정은 브라우저마다 차이가 난다. 이는 서버에서 html,css,javascript 자료를 받아서 사용자의 화면에 구현하는 장치, 즉 '브라우저 엔진'이 브라우저 마다 차이나기 때문이다.
브라우저 중 전세계 사용자의 비중이 높은 크롬, 파이어폭스, 사파리는 각각 Blink, Gecko, Webkit이라는 브라우저 엔진을 사용한다.
서로 다른 브라우저라도 동일한 엔진을 사용하기도 한다. 크롬의 Blink엔진은 오페라에서도 이용하고 있다. 따라서 브라우저마다 다른 렌더링 원리는 브라우저 엔진의 차이로 볼 수도 있다.(물론, 동일한 엔진을 쓰더라도 렌더링 과정이 조금씩 다를 순 있다.)
2. 브라우저의 기본구조 및 작동과정
사용자가 브라우저에서 뭔가를 할때 브라우저는 어떤 과정으로 작동할까?
브라우저를 구성하는 요소는 이렇다.
- 사용자 인터페이스
- 브라우저 엔진
- 자료저장소
- 렌더링 엔진
- 통신
- 자바스크립트 해석기
- UI 백앤드
1) 사용자 인터페이스
.사용자에게 보여지는 페이지 창에서 URL에 상관없이 존재하는 공통 요소이다. 이는 표준 명세가 없으나, 오랜 세월이 지나며 관습적으로 서로 유사해졌다.
- URI를 입력할 수 있는 주소 표시 줄
- 이전 버튼과 다음 버튼
- 북마크
- 새로 고침 버튼과 현재 문서의 로드를 중단할 수 있는 정지 버튼
- 홈 버튼
2) 브라우저 엔진
사용자가 사용자 인터페이스에서 뭔가를 입력하면 이를 받아들여 렌더링 엔진을 작동시킨다.
브라우저 엔진과 렌더링 엔진은 별도로 볼순 있으나, 둘의 관계가 워낙 밀접하여 따로 보는 경우는 잘 없다.
3) 렌더링 엔진
사용자의 요청을 받아들여 페이지를 구현한다.
사용자가 특정 URL로의 접속을 요청하면 렌더링 엔진의 작동과정은 이렇다.
우선, 통신 기능으로 서버에 해당 URL의 HTML,CSS,Javascript 자료를 요청한다.
자료를 받은 후, 렌더링 엔진은 HTML과 CSS파일을 처리하고, Javascript 파일은 자바스크립트 해석기라는 별도의 소프트웨어로 보내 처리한다.
렌더링엔진의 작동과정은 이렇다.
- 파싱
: 사람이 작성한 HTML,CSS 코드를 컴퓨터가 이해가능한 언어로 치환하는 과정
- 렌더링 트리 구축
: 파싱으로 생성된 DOM 트리와 CSSOM(스타일규칙)을 결합하는 과정
- 레이아웃/리플로우
: 렌더링트리에 담긴 스타일규칙에 맞게 DOM 노드들을 페이지에 구현하는 과정
각 요소의 크기와 위치를 계산하고 배치하는 과정에 해당한다.
- 페인트
: 레이아웃이 완료된 요소들을 시각적으로 그리는 과정
UI 백엔드가 이를 담당한다.
- 레이어 결합/composite
: 포토샵의 레이어를 생각하면 이해가 빠르다.
화면에 나타나는 페이지는 여러개의 레이어를 쌓아 결합시킨 결과인데,
컴포짓이 이 과정에 해당한다.
이 과정이 끝나면, 최종적으로 페이지가 완성된다.
여기서 중요한건 이 과정들이 병렬적으로 이뤄진다는 것이다. 즉, 브라우저는 HTML의 요소들을 전부 파싱작업 하고나서
렌더링 과정으로 넘어가는 것이 아니라, 한 부분을 파싱하고 나서 다음과정들을 하고, 다시 다른 부분을 파싱하고나서 다음과정을 진행하는 방식이다. 파싱부터 그 이후의 렌더링과정은 조금씩 동시에 진행된다.
4) 자료저장소
브라우저가 요청하는 URL은 일반적으로 서버에서 통신으로 가져오지만,
자주 이용하는 사이트나 특별한 경우에는 이를 매번 통신으로 호출하는 번거로움을 피하기 위해
자료 저장소에 저장해놓는다. 이런 경우에 자료저장소에 있던 자료를 '캐시'라고 부른다.
5) 작동 과정의 예시
크롬에서 URL에 사이트 A의 주소를 입력했다고 치자.
그럼, 브라우저 엔진은 사용자 인터페이스로 입력된 URL 값을 받아서 렌더링 엔진에 넘겨주고, 렌더링 엔진은 통신을 통해 서버에 해당 URL에 해당하는 HTML,CSS,Javascript 자료를 요청한다. 서버가 브라우저의 요청에 응답해 자료를 보내주면 렌더링 엔진의 웹 페이지 구현이 시작된다.(만약, 해당 URL을 자주 이용한다면 사용자의 자료저장소에 저장되어 있을 수 있다. 이럴 경우, 브라우저 엔진은 자료저장소에서 바로 URL자료를 받아 렌더링 엔진에 보내고 렌더링엔진은 구현을 바로 시작한다.)
6) 정리
(1) 작동과정
사용자 인터페이스=>브라우저 엔진=> 렌더링 엔진=> 통신 => 렌더링엔진, 자바스크립트 해석기
여기서 렌더링 과정은
파싱=>결합=> 렌더링 트리 구축=> 레이아웃 => 페인트 => 컴포짓
3. 렌더링 과정
이제 렌더링 과정을 구체적으로 보자.
1) 파싱
파싱은 소스코드를 의미있는 부분마다 자르는 과정이다.
HTML 파싱은 HTML의 태그, 텍스트, 이미지 등을 파싱하여 DOM node로 변환되고 이 노드들 간의 구조로 만들어진 DOM 트리에 추가된다. HTML을 굳이 DOM으로 바꾸는 이유는 사용자와의 상호작용(클릭, 스크롤, 마우스 가져다대기 등등)을 위해서다,
HTML의 본질은 mark-up 언어이므로, 브라우저 화면 상에 정보를 띄울 수 만 있고 동적인 상호작용이 불가능하다.
그래서 이를 동적으로 상호작용 할 수 있도록 javascript를 이용하는 것인데, HTML은 DOM 형식으로 바뀜으로서 javascript로 제어할 수 있게 되는 것이다,
CSS 파싱은 CSSOM이라는 문서를 생성한다.
파싱으로 생성된 스타일 규칙은 자신이 가리키는 DOM 노드에 대한 정보를 담고 있다.
2) 어테치먼트
dom트리 내 dom node와 cssom을 결합하는 과정이다. dom node들은 기본적으로 스타일을 가지고 있는데,
가령, html의 <h1> 태그를 javascript로 불러와서 console.log 해보면, 프로퍼티로 width나 height, style 등의 하위 프로퍼티가 존재한다.
어태치먼트는 CSSOM에 담겨있는 스타일 정보를 dom node에 삽입하는 과정이다.
이 과정은 dom node내에 내장된 어태치먼트 메소드를 통해 자동 실행된다. 이 과정이 끝나면 렌더 오브젝트로 변환되는데, 앞서 말했듯, 이 과정은 점진적으로 html 파싱요소마다 하나씩 먼저 실행된다.
(즉, 싸그리 모두 파싱하고 싸그리 모두 어태치먼트하고 싸그리 모두 렌더오브젝트화 하는 과정이 아니라
하나씩 진행된다.)
3) 렌더트리 구축
렌더 오브젝트간의 관계, 크기, 위치 값을 계산하는 과정이다.
여기서 중요한건, HTML의 모든 요소가 렌더 오브젝트가 되진 않는다는 점이다.
Head 태그의 요소들은 사용자가 보는 페이지상 보이지 않아도 되므로 이 과정에 해당되지 않는다.
display 스타일이 none으로 설정된 것들도 마찬가지다.
4. 렌더링 과정 2
1) 렌더트리 레이아웃/리플로우
렌더링트리에 맞게 요소들을 배치하는 과정이다.
2) 렌더트리 페인트
렌더 오브젝트 내 페인트 메소드를 호출하여 스타일 규칙에맞게 오브젝트를 시각화한다.
3) 렌더트리 합성/컴포짓
페인트가 레이어 하나하나를 생성하는 과정이라면, 컴포짓은
각 레이어를 하나로 결합하여 최종적으로 페이지를 완성하는 과정이다
6. 브라우저 최적화 1 : 로딩 최적화
로딩 최적화는 화면이 흰 상태로 뜨는 시간을 줄여 사용자를 지루하지 않게 하는 것이 목적이다..
사용자가 한 페이지를 들어갔는데, 로딩 시간이 몇 십초 단위로 걸리면
금새 실증나서 나가버릴 수도 있다.
(그래서 로딩 시간 단축은 사용자의 유의미한 머무름을 증가시키는 기능이 있다.)
이는 크게 두가지 방식이 있다.
- 브라우저 기준 로딩 최적화
- 사용자 기준 로딩 최적화
1) 브라우저 기준 로딩 최적화
브라우저가 서버로부터 소스 자료를 받아오고 DOM노드를 렌더링하며 애니메이션이나 이벤트를 실행할 준비를 하고 실행하는 일련의 과정을 개선하는 것이다. 이는 최초의 렌더링 과정에 해당한다.
첫번째 방법은 javascript나 css 같은 html 외적 소스의 개선이다.
javascript의 경우, 실행되는 순간 HTML 렌더링이 중단되므로, 페이지의 빈 화면이 보여지는 시간이 증가한다. 따라서 html에서 스크립트 태그를 body의 가장 아래로 보내거나 defer를 추가해주는 것이 바람직하다.
css의 경우, external css는 html과 css style을 분리시켜 개발자의 유지 및 보수에 편리하나 통신으로 css 소스 자료를 가져오는 시간이 걸릴 수 밖에 없다. 따라서, inline 방식으로 전환할 수 있는 건 전환하는 것이 좋다,
(external을 쓰지 말라는 얘기가 아니라 너무 많이 만들지 말라는 얘기이다.)
2) 사용자 기준 로딩 최적화
앞서 말했듯, 브라우저는 부분적으로 조금씩 html을 파싱하여 보여준다.
따라서, 전체 과정의 시간을 줄이는 것 외에도 사용자에게 가장 필요한 정보를 먼저 로딩하는 방식으로 코드를 짜는 것이 중요하다.
위의 과정에서 핵심은 'first meaningful paint'를 앞당기는 것이다.
여기 사용되는 방법으로는
- spa
: 뷰나 리엑트
프레임워크 로딩 후 ajax 콜 의미있는 화면
- ssr(서버 사이드 랜더링)
: ajacx
- 프리 랜더러
정도가 있다.
7. 브라우저 최적화2 : 렌더링 최적화
렌더링 최적화가 필요한 이유는 뭘까.
개발자가 소스코드로 짠 애니메이션은 브라우저가 그 과정을 수십개의 페이지로 렌더링하여서 이어붙이는 과정이다.
따라서 애니메이션이 보여지는 짧은 시간 안에 페이지를 충분히 많이 구현해야 애니메이션이 끊기거나 느려지지 않는다.
그렇다면 페이지 한 프레임이 몇 초 안에 구현되야 할까.
요즘 기기들은 대부분 60FPS를 지원하므로, 1초에 60프레임, 즉 1프레임당 16ms 정도 밖에 시간 여유가 없다. 따라서 렌더링 최적화는 사용자에게 부드러운 이미지를 보여주기 위한 필수작업이다.
이 작업은 크게 세 가지 방식으로 가능하다.
- 레이아웃 스레드 최적화
- 가상 돔(virtual DOM)
- 웹 워커
이 중 아래 두가지는 아직 필자의 지식으로는 이해가 어려운 부분이라 첫번째만 살펴보겠다.
1) 레이아웃 스레드 최적화
애니메이션 실행 시, 브라우져는 짧은 시간 내에 렌더 오브젝트의 스타일 값을 재계산하고 레이아웃=>페인트=> 컴포짓 과정을 반복적으로 실행한다. 이때, 레이아웃처럼 연산비용이 큰 작업의 반복으로 렌더링 성능이 떨어지는 현상을 '레이아웃 스레싱'이라고 부른다
이를 해결하려면 CSS에서 레이아웃 작업을 해야하는 프로퍼티를 최소화하고 이를 페인트나 컴포짓만 실행하는 속석으로 대체해야 한다.
예컨대, 좌로 움직이는 애니메이션을 구현할때, left는 전자에 해당하고 transform: translate는 후자에 해당한다.
또한, 사용하지 않는 요소들은 display:none으로 처리함으로써
렌더링 과정에서 제외시켜준다.
'브라우저 관련 공부' 카테고리의 다른 글
[브라우저] CORS(란 무엇인가? (0) | 2024.03.24 |
---|