브라우저가 웹 페이지를 화면에 표시하기 위해 거치는 과정입니다.
브라우저가 HTML 파일을 받아 HTML 파서를 통해 문자열로 변환하고, 이 문자열을 다시 HTML 토큰으로 변환합니다. 이 HTML 토큰은 각각의 태그와 그 안에 포함된 텍스트, 속성 등을 의미합니다.
HTML 토큰이 생성되면, 브라우저는 이를 기반으로 DOM 트리를 생성합니다. DOM 트리는 HTML 문서의 구조를 트리 형태로 표현한 것으로, 각 태그가 노드가 되어 부모-자식 관계를 형성합니다.
<!DOCTYPE html>
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
Document
└── <html>
├── <head>
└── <body>
└── <h1>
└── "Hello, World!"
브라우저는 CSS 파일을 파싱하여 문자열로 변환한 뒤 CSS 규칙으로 나눕니다. 각 CSS 규칙은 선택자(selector)와 선언(declaration)으로 구성되는데, 선택자는 스타일을 적용할 HTML 요소를 정의하고, 선언은 적용할 스타일을 정의합니다.
이 CSS 규칙들을 기반으로 CSSOM 트리를 생성합니다. CSSOM 트리는 DOM과 유사하게 트리 구조를 가지며, 각 노드는 해당 노드에 적용될 스타일 정보를 포함합니다.
h1 {
color: red;
font-size: 24px;
}
CSSOM
└── h1
├── color: red
└── font-size: 24px
DOM과 CSSOM이 생성되면 브라우저는 DOM과 CSSOM을 결합하여 렌더 트리를 생성합니다. 렌더 트리는 화면에 실제로 표시될 요소들로만 구성됩니다. 예를 들어 display:none 속성이 있는 요소는 렌더 트리에 포함되지 않습니다. 반면 visibility:hidden 속성이 있는 요소과 같이 렌더링은 되어야 하지만 화면에 표시되지 않아야 하는 경우는 렌더 트리에 포함됩니다.
렌더 트리의 각 노드는 DOM 트리의 요소와 연결되며, CSSOM 트리에서 해당 요소에 적용된 스타일 정보를 포함합니다. 즉, 렌더 트리는 HTML 문서의 구조와 각 요소의 스타일 정보를 모두 포함한 트리입니다.
렌더 트리가 생성된 후, 브라우저는 이 트리를 사용해 각 요소의 정확한 위치와 크기를 계산하는 레이아웃 작업을 시작합니다.
이 계산은 화면의 뷰포트 크기와 같은 정보에 의존합니다. 따라서 화면 크기가 변경되거나 스타일의 변경이 일어나면 브라우저는 레이아웃 과정을 다시 수행해야 합니다. 이러한 과정을 리플로우(Reflow)라고 합니다. 리플로우가 너무 빈번하게 발생할 경우 성능에 영향을 줄 수 있기 때문에 이를 최소화하는 것이 중요합니다.
레이아웃이 완료되면, 브라우저는 각 요소를 실제로 화면에 그리는 페인팅 작업을 시작합니다. 페인팅 단계에서는 텍스트, 색상, 그림자, 이미지 등 모든 시각적 요소가 화면에 그려집니다.
페인팅은 화면에 표시될 그래픽 요소를 생성하는 과정이기 때문에, 성능에 큰 영향을 줄 수 있습니다. 특히, 복잡한 그래픽이나 애니메이션이 포함된 경우 페인트 작업이 많아져 성능이 저하될 수 있습니다.
마지막으로 브라우저는 화면에 그려질 요소들을 각각의 레이어로 분리하고, 이 레이어들을 결합하여 최종 화면을 구성합니다. 이 과정에서 브라우저는 레이어를 GPU로 전달하여 각 레이어를 빠르게 합성합니다. 컴포지팅 단계는 GPU 가속을 활용하여 성능을 최적화하고, 화면에 최종적으로 표시되는 결과를 빠르게 생성하는 데 중요한 역할을 합니다.
transform과 opacity와 같은 속성은 레이아웃이나 페인트 과정을 거치지 않고 바로 컴포지팅 단계에서 처리됩니다. 이 덕분에 이러한 속성을 사용하는 애니메이션은 더 부드럽고 빠르게 실행될 수 있습니다.