TIL21. 브라우저의 렌더링 처리 과정(1)

Ben·2022년 4월 21일
0

Today I Learned

목록 보기
21/57

Today I Learned

오늘은 저번에 브라우저 렌더링 CSS에 이어서 다음을 작성하고자 한다.

렌더 트리 구성

렌더 트리를 구성하는 과정은 Webkit 기준 렌더 트리, Gecko 기준 frame tree라고 한다.

렌더 트리를 구성하는 과정

  1. html 파싱으로 얻은 DOM Tree의 루트 노드부터 탐색하며 렌더 트리에 표시한다. 이때, <head>, <meta>, <script>등의 시각적 요소가 없는 태그들은 렌더 트리에 표시되지 않는다. 또한, 시각적 요소 태그들도 display: none 스타일을 가진 태그들 역시 렌더트리에 표시되지 않는다.
  2. 렌더 트리에 표시된 노드와 적절히 일치하는 스타일 규칙을 찾아 연결한다.
  3. 콘텐츠와 스타일 규칙을 포함하여 노드를 내보낸다.

렌더 트리와 DOM Tree는 1대1로 매칭되지 않는다.

이미 렌더 트리를 구성하는 과정 1번에 나와 있지만, DOM Tree와 렌더 트리는 1대1로 매칭되지 않는다. 크게 두 가지의 경우를 생각해 볼 수 있다.

  1. 시각적 요소를 가지지 않은 DOM의 경우 렌더 트리에 표시되지 않는다.
    • <head>, <meta>, <script> 와 같은 시각적 정보를 표시하지 않는 태그들은 렌더 트리에 표시되지 않는다.
    • display: none 속성을 갖는 엘리먼트 역시 렌더트리에 포함되지 않는다.

      Q: display: nonevisibility: hidden의 차이점?
      A: display: none은 렌더 트리에 포함되지 않고 레이아웃을 차지하지 않지만, visibility: hidden은 화면 상에서 가려놓을 뿐, 레이아웃에 포함되어 있다. 마찬가지로 렌더 트리에 표시된다.

  2. 하나의 엘리먼트가 여러 스타일 객체에 대응하는 경우도 있다.
    • <select> 태그의 경우 제목과 옵션들, 그리고 버튼들로 구성되어 있으며, 각각 스타일 객체에 대응된다.

스타일을 구성하는 과정은 매우 어렵다.

스타일 속성은 매우 방대하다. 수 많은 스타일 속성을 수용하면서 메모리 문제를 야기하게 된다.
중첩된 css selector의 경우, 해당 노드를 찾는데 성능 문제를 야기할 수 있다.

브라우저가 스타일을 최적화하는 방법

  • 웹킷의 경우: 웹킷은 여러 DOM이 특정 조건 하에서 하나의 스타일 객체를 참조할 수 있다. 예를 들면, 같은 클래스를 가지고 있거나 같은 속성을 가지고 있는 엘리먼트들은 하나의 스타일 객체를 참조하는 방식으로 최적화가 진행된다.
  • 파이어폭스(Gecko)의 경우: 파이어폭스는 스타일 문맥 트리와 규칙 트리가 추가로 존재한다. 스타일 문맥 트리에서 모든 비율로 이루어진 값들은 계산되어 절댓값으로 저장한다. 또 노드 사이에서 중복 계산을 피하기 위하여 값을 공유하기도 한다. 그리고 모든 일치하는 규칙들은 하나의 트리에 저장된다. 트리는 규칙과 일치하는 모든 경로를 포함한다.

LayOut(배치 과정)

렌더 트리의 렌더러들은 크기와 위치 정보를 가지고 있지 않은 상태다. 레이아웃 과정을 거쳐 위치와 크기를 계산하여 노드들을 배치한다. 좌표는 횡축으로 X, 종축으로 Y 값을 가지며, 좌상단이 0, 0의 위치를 갖는다.

브라우저가 배치하는 과정

  1. 먼저 부모의 너비를 계산한다.
  2. 부모의 너비를 계산한 뒤, 자식 노드가 있다면, 자식 노드로부터 누적된 높이와 border, padding, margin을 합하여 부모 노드의 높이를 구한다.
  3. 구한 부모의 높이를 부모의 부모로 전달하여 이 과정을 반복한다.

너비의 계산은 어떻게 이루어지는가?

블록의 너비는 렌더러의 너비와 여백, 테두리를 이용하여 계산한다.
availableWidth = clientWidth - paddingLeft - paddingRight
만약 얻은 너비의 값이 최소 너비보다 작다면 최소 너비가 availableWidth가 되고, 얻은 너비 값이 최대 너비보다 크다면 최대 너비가 availableWidth가 된다.

페인트 과정

페인트 과정은 계산된 크기, 위치를 바탕으로 DOM을 화면에 그리는 과정이다. 이때 그리는 순서는 다음과 같다.

  1. background-color
  2. background-image
  3. border
  4. children
  5. outline

Reflow와 Repaint

스타일에 변경이 있거나 콘텐트가 변경될때, 다시 레이아웃을 설정하고 그리는 작업을 하게 된다. 이것은 사소한 규칙이 변경되었더라도 동일하게 적용되므로, 계속 재렌더링이 일어나는 것은 매우 비효율적인 동작이다.

엘리먼트들의 크기와 위치가 변할 경우 -> reflow 발생. reflow는 항상 repaint를 수반함
엘리먼트의 border-radius 등 스타일이 변할 경우 -> repaint 발생

reflow와 repaint 최소화 하기

가장 최선의 방법은 reflow, repaint를 발생시키는 스타일을 사용하지 않는 것이지만, 이는 불가능에 가깝다.

  1. width, height, border 등을 사용하지 않고 웹 페이지를 만들 수 있을까...?
  2. 더 좋은 방법은 virtualDOM을 사용하는 것이다.

virtualDOM?

자바스크립트 객체를 DOM 형식으로 표현한 것이며, 모든 변경 정보들을 저장한 뒤 한번에 렌더링 하는 방식을 취하고 있어서, reflow, repaint 현상을 최소화 해준다. 다만, 요소들이 많아질수록 요소를 변경하기 위한 탐색 시간과, 메모리에 항상 올려두므로 메모리 사용양이 많다는 단점들이 존재한다.

CSS 박스 모델

하나의 영역은 content, padding, border, margin으로 이루어져있으며, 안쪽에서부터 바깥쪽으로 이루어진다.

CSS 적용 우선 순위

  1. 브라우저 일반 선언
  2. 사용자 일반 선언
  3. 저작자 일반 선언
  4. 저작자 중요 선언
  5. 사용자 중요 선언

순으로 이루어져 있으며, CSS Selector는 다음의 우선순위를 갖는다.

  1. !important
  2. #id
  3. .class, :abstract class
  4. tagname

만약 동일 우선 순위를 가질 경우, 아래쪽에 작성한 CSS 규칙이 우선 순위를 갖는다.

마치며

간단히 정리했음에도 불구하고 엄청난 양... 더 깊게 이해하려면 더 많은 시간을 투자해야 할 것 같다. 아직 배치쪽에 깊은 지식들이 남아있는데, 시간이 없어서 다 읽어보지 못했다. 다음편에서는 좀 더 읽어보고 작성해야겠다.

출처

https://d2.naver.com/helloworld/59361
https://setisigns.tistory.com/437

profile
New Blog -> https://portfolio-mrbartrns.vercel.app

0개의 댓글