브라우저 작동 원리(5)-레이아웃

렌더러가 생성되어 트리에 더해질 때 크기위치에 대한 정보는 가지고 있지 않습니다. 이러한 값을 계산하는 게 배치(layout)리플로우(reflow)입니다

HTML은 흐름(flow)에 기반한 배치(layout) 모델을 사용하는데 이는 보통 단일 경로(single-pass)를 통해 위치 정보를 계산할 수 있다는 것을 말합니다

일반적으로 흐름 속에서 나중에 등장하는 요소들은 먼저 등장한 요소의 위치와 크기에 영향을 주지 않기 때문에, 배치는 좌->우위->아래로 진행됩니다. HTML의 table은 하나 이상의 경로를 요구하기 때문에 예외사항에 포함 됩니다

좌표계(coordinate system)기준점(root frame)으로부터 상대적인 위치를 정하기위해 상단(top/y)좌단(left/x) 좌표를 사용합니다

배치반복적인 과정으로, HTML 문서의 html요소에 해당하는 root 렌더러에서 시작됩니다. 배치는 프레임 계층의 일부나 전부를 통해서 반복되며, 각 렌더러를 위한 크기위치 정보를 계산합니다

root 렌더러의 좌표는 0,0이고 브라우저의 창이 보이는 만큼의(viewport) 면적을 가집니다

모든 렌더러layout이나 reflow메소드를 가지는데 각 렌더러는 배치해야할 자식의 layout 메소드를 호출합니다

더티 비트 시스템(Dirty bit system)

간단한 변경 때문에 전체를 다시 배치하지 않기위해 브라우저는 더티 비트 시스템을 사용합니다. 변경되거나 추가된 렌더러는 자신과 자기의 자식들을 더럽다고 표시합니다 (더러움 = 재배치가 필요함)

두가지 종류의 flag가 사용됩니다 : 각각 더티자식이 더티함(렌더라 자신은 괜찮지만 자식 중 적어도 하나는 재배치가 필요하다는 의미)

전역(Global) 배치와 점증(incremental) 배치

배치는 전체 렌더 트리에서 발생할수도 있는데 이걸 전역 배치라고 합니다. 이런 상황은 다음과 같은 경우에 발생합니다

  1. 글꼴 크기 변경과 같이 모든 렌더러에 영향을 주는 전역 스타일 변경
  2. 화면 크기 변경에 의한 결과

배치더티 렌더러가 배치되는 경우만 점증되는데, 추가적인 배치가 필요하기 때문에 약간의 손실이 발생할 수 있습니다

점증 배치렌더러가 더티일때 비동기적으로 이루어집니다. 예를 들어 네트워크로부터 추가 내용을 받아서 DOM 트리에 추가된 다음 새로운 렌더러(더티로 취급됨)가 렌더 트리에 추가되는 경우입니다



비동기 배치와 동기 배치

점증 배치비동기로 실행됩니다

파이어폭스점증 배치를 위한 reflow 명령을 쌓아놓고 스케쥴러는 이 명령을 한번(batch 방식)에 실행합니다. 웹킷점증 배치를 실행하는 타이머를 가지는데 트리를 탐색해 더티 렌더러를 배치합니다

offsetHeight같은 스타일 정보를 요구하는 스크립트는 점증 배치동기적으로 실행합니다. 전역 배치는 주로 동기적으로 수행됩니다

가끔식 배치는 스크롤 위치변화 같은 일부 속성들 때문에 처음 배치된 이후 callback으로 실행됩니다

최적화

배치크기 변경이나 렌더러 위치 변화 때문에 실행되는 경우, 렌더러의 크기는 다시 계산하지 않고 캐쉬에서 가져옵니다

어떤 경우에는 root로부터 시작하지않고 하위 트리만 수정이 되는 사례도 있습니다. 이건 입력 필드에 텍스트를 입력하는 것처럼 변화되는 범위가 한정적(local)이여서 주변에 영향을 주지 않는 경우에 발생합니다. 만약 입력 필드 외부에서 텍스트가 입력됬다면 root부터 시작됩니다

배치과정

배치 과정은 주로 다음과 같은 형태로 진행됩니다

  1. 부모 렌더러가 자신의 너비 결정
  2. 부모가 자식을 검토
    2-1. 자식의 렌더러 배치 (x,y 설정)
    2-2. 필요하다면 자식의 배치 호출하여 높이를 계산(부모와 자식이 더티하거나, 전역 배치 상태이거나 등등)
  3. 부모는 자식의 중첩된 높이에 여백(margin), 패딩(padding)을 사용해 자신의 높이를 설정합니다. 이 값은 부모 렌더러의 부모가 사용합니다
  4. 더티 비트 플래그를 제거합니다

파이어 폭스상태(state) 객체(=nsHTMLReflowState)를 배치(=reflow)를 위한 매개변수로 사용합니다. 상태 객체는 부모의 너비를 포함합니다

파이어 폭스의 배치 결과는 매트릭스(metrics) 객체(=nsHTMLReflowMetrics)입니다. 이 객체는 렌더러의 계산된 높이를 가지고 있습니다

너비 계산

렌더러너비컨테이너(포함하는 블록)의 너비렌더러의 너비(width), 여백(margin), 경계선(border)를 가지고 계산됩니다

예를 들어 다음과 같은 div 요소가 있을 때

<div style="width: 30%"/>

웹킷은 다음과 같이 계산합니다(RenderBox 클래스의 calcWidth 메소드)

컨테이너의 너비는 availableWidth와 0 사이의 최대 값입니다. 이 경우의 availableWidth는 다음과 같이 계산됩니다

clientWidth() - paddingLeft() - paddingRight()

clientWidthclientHeight는 경계선과 스크롤바를 제외한 내부의 영역을 의미합니다

요소의 너비는 width속성의 값입니다. 여기서는 컨테이너 너비의 백분율이 절대값으로 변환될 것입니다

수평(좌우)의 너비와 패딩 값이 추가됩니다

여기까지가 미리 획득한 너비(clientHeight)의 계산이고, 이제 최소 너비최대 너비를 계산해야합니다

만약 미리 획득한 너비가 최대 너비보다 크다면 최대너비가 사용되고, 만약 미리 획득한 너비가 최소 너비(더 나눠지지 않는 가장 작은 단위)보다 작으면 최소 너비가 사용됩니다

배치가 필요한 경우 값들은 캐쉬에 저장되지만 너비는 변경되지 않습니다

줄바꿈(Line Breaking)

렌더러가 배치되는 동안 을 바꿀필요가 있을 때, 배치는 중단되고 그 필요를 부모에게 전달(propagates)합니다. 부모는 그러면 추가 렌더러를 생성하고 이것들의 배치를 호출합니다

참고 및 출처

https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/

https://d2.naver.com/helloworld/59361

좋은 웹페이지 즐겨찾기