웹 브라우저에는 두 개의 엔진이 있다.
렌더링 엔진
사용자가 볼 화면을 그려내는 역할 (내용 정보인 HTML과 서식정보인 CSS 등을 읽어들여 사람이 읽을 수 있는 문서로 표시하는 역할. (즉, HTML과 CSS를 파싱하여 최종적으로 화면에 그려주는 역할)
자바스크립트 엔진
자바스크립트 코드를 읽어내 기능을 작동시키는 역할
우리는 렌더링에 대해서 살펴볼 것이기 때문에, 렌더링 엔진의 역할에 대해서 조금 더 살펴보도록 하겠다.
렌더링 엔진은 웹사이트의 소스코드를 읽어 실제 어떤 요소들이 어떤 크기, 너비로 배치되는지, 텍스트의 크기는 얼마나 커야 하는지, 색은 어떤 색이어야 하는지, 간격은 얼마로 배치해야하는지 등을 계산해 실시간으로 그려준다.
렌더링 엔진의 목표는 크게 다음과 같이 말할 수 있겠다.
브라우저가 서버로부터 HTML 문서를 모두 전달 받는다. (Loader가 서버로부터 HTML을 불러옴)
렌더링 엔진은 전달 받은 HTML 문서를 파싱하여 DOM 트리를 구축한다.
외부 CSS 파일과 함께 포함된 스타일 요소를 파싱하여 CSSOM 트리를 만든다. (CSS Object Model) CSSOM은 DOM이 어떻게 화면에 표시될 지를 알려주는 역할을 한다.
DOM 트리와 CSSOM 트리를 합쳐 렌더 트리(Render Tree)를 구축한다. 렌더 트리는 화면에 표시되어야 할 모든 노드의 컨텐츠, 스타일 정보를 포함하고 있는 트리이다.
(DOM 트리의 최상단인 document 객체부터 각 노드를 순회하면서 각각에 맞는 CSSOM을 찾아서 규칙을 적용한다. 그러면서 렌더와 관련된 요소들을 렌더 트리에 포함시킨다. 이 때, meta 태그나 display: none;
속성을 가진 요소들은 렌더와 관계가 없기 때문에 렌더 트리에 포함되지 않는다.)
렌더 트리의 요소들의 크기와 위치를 계산한다.
계산된 크기와 위치에 맞게 화면에 출력한다. Layout
- Paint
- Composite
의 세 단계로 이루어진다.
뷰포트 내에서 요소들의 정확한 위치와 크기를 계산하는 과정.
박스 모델에 따라서 텍스트나 요소의 박스가 화면에서 차지하는 영역이나 여백, 그리고 이외의 스타일 속성이 계산된다. 이 때, CSS에서 %
나 em
같은 상대적인 단위를 사용했을 때에는 뷰포트에 맞춰서 픽셀 단위로 변환된다.
레이아웃의 높이, 너비, 그리고 위치 등에 변화 그리고 DOM이 추가되거나 삭제되면 Reflow
가 일어난다. (즉, Layout 과정이 다시 발생하는 경우를 Reflow
라고 한다.)
Reflow
는 위의 그림에서 보이는 부분을 모두 수행해야하며 다른 모든 노드의 위치를 다시 계산하고 영향을 받은 부분을 찾아내어 다시 Paint한다.
❗ Reflow (다시 Layout)이 발생하는 경우
- 주로 요소의 크기나 위치가 바뀔 때
- 혹은 브라우저 창의 크기가 바뀌었을 때
위의 Layout 과정에서 렌더링 엔진이 각 요소들이 어떻게 생겼고 이를 어떻게 보여 줄 지 알게 되면 마지막으로 화면에 실제 픽셀로 그려지도록 변환하는 과정을 거치는데, 이것이 바로 Paint 과정이다.
이 과정에서 렌더 트리에 포함된 요소들이나 텍스트, 이미지들이 실제 픽셀로 그려진다.
위의 Reflow와 비슷하게 Repaint 상황도 있는데, Repaint가 되는 경우를 알아보자.
❗ Repaint가 발생하는 경우
- 주로 배경 이미지나 텍스트 색상, 그림자 등 레이아웃의 수치를 변화시키지 않는 스타일의 변경이 일어났을 때 발생
이와 같은 경우는 Layout 과정이 발생하지 않기 때문에 성능상으로 좀 더 이점을 가진다.
레이어(Layer)란, 포토샵의 레이어와 비슷하게 페인팅 할 영역을 나누어 놓는 것을 의미하는데, 크롬의 경우에는 Layout 과정 이후에 정해진 기준이나 필요에 의해서 브라우저가 레이어를 생성한다. 그리고 렌더 트리에 있는 노드 객체들은 생성된 레이어에 포함되게 된다. 이 레이어들은 트리 형태로 구성되며, 렌더링 엔진이 각 레이어를 프린팅 과정에서 각각 그려 준 다음에 하나의 비트맵으로 합성해서 페이지를 완성한다.
❗ 레이어의 합성만 다시 발생하는 경우
- Layout과 Paint를 수행하지 않고 레이어의 합성만 발생하기 때문에 성능상으로 가장 큰 이점을 가짐.
https://csstriggers.com 을 이용하면 어떤 css 속성이 layout, paint, composite 중에 어떤 것을 일으키는 지 렌더링 엔진 별로 확인할 수 있다.
개발자 도구를 켜고 맨 오른 쪽 쩜쩜쩜 버튼(?)을 눌러주고, More tools에 들어가면 Rendering이라는 메뉴가 있다. 그걸 눌러서 추가해주자.
그러면 맨 밑에 Rendering 탭이 뜨는데, 거기서 Paint flashing
이라고 하는 속성을 켜주자. 그러면 브라우저 화면에서 어떤 부분이 다시 paint 되는지 알 수 있다.
애니메이션을 구현할 때 left
속성 말고 transform
속성으로 대체해서 사용하게 된다면 repaint 과정 없이 composite 과정만 거치기 때문에 훨씬 부드러운 애니메이션을 만들어 낼 수 있도록 최적화할 수 있게 된다.