본문 바로가기

Front-End/ETC

CSS 렌더링 에 대하여

CSS 렌더링

'CSS 렌더링'이란 그림을 그릴 영역을 계산하고 영역을 채우는것.


웹에있는 CSS 렌더링 시스템은 여러 분야의 렌더링 시스템을 받아들여 왔기 때문에 난잡하고, 표준화 되어 있지 않다. 

CSS 는 버전이 아니라 레벨로 관리된다.


1. CSS LEVEL 1 - A4 한장으로 정의할 정도로 별거없음


2. CSS LEVEL 2 + Module 의 개념 추가 

- 모듈로 관리되기 시작하면서 모듈별로 버전이 관리되게 되고 CSS3 로 전체 모듈의 레벨을 한번에 관리하는것이 불가능하게됨)


3. CSS LEVEL 2.1 

- CSS 2.1 에 포함 된 모듈 중 모듈의 버전이 3 인것들을 CSS 3 라고 부르게 됨)


W3C 의 영향력이 약해지면서 Draft 되지 않을 것들을 브라우저에서 적용했고, W3C 에서 새로운 그룹을 만들어 브라우저별로 Draft 사용할수도 있게 만들어냈다. WICG 에서 나오는 제안은 크롬에 반영한 후W3C 에 Draft 되기도 한다.




NORMAL FLOW


- CSS 에서 사용하는 고유명사

- CSS2.1 Visual formatting model

- CSS Position 에서의 static, relative, absolute, fixed, inherit 는 추상적인 위치를 결정하게 하는 시스템

- Normal Flow 는 static, relative 에서만 적용됨.

- blocking formatting contexts, inline formatting contexts 두가지의 계산방법이 존재. (사실읜 세가지)



BFC(Block Formatting contexts)


- 페이지의 width 한줄을 다 차지함.

- 다음 Block 의 위치를 계산할때 첫번째 Block 요소의 아래에 위치하게 됨.



IFC(Inline Formatting contexts)


- content 의 width 만큼을 차지함.

- 다음 Inline 의 위치를 계산할 때 첫번째 Inline 요소가 끝나는 위치에 위치하게 됨.

- BaseLine 의 개념이 나옴.



Example (BFC, IFC)



<div style="width: 100px; background: tomato;">

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

</div>



위의 HTML 코드에서 <div/> 블럭 영역을 'aaa...' 가 뚫고 나가는 이유는 하나 이상의 공백이 없는 연속된 문자열을 <span/> 과 같은 하나의 Inline 요소로 인식하게 된다. 다만 연속된 문자열에 공백이 하나라도 들어가게 되면 공백이 없는 문자열을 Inline 요소로 하나로 인식하여 다음 라인에 문자열을 추가하게 되는데, 이런방식을 사용하지 않으면 아래와 같은 방식을 사용해야한다.



<div style="width: 100px; background: tomato;">

aaaaaaaaaaaaaaaaaa

aaaaaaaaaaaa

aaaaaa

</div>

 


위의 HTML 코드는 브라우저에 word break 속성을 추가하는 방식으로 'aaa...' 문자열의 'a' 문자 하나하나를 인라인 요소로 생각하게 만드는 방법인데, 띄어쓰기 되어있는 영역을 기준으로 문자열이 엔터처리 된다. 다만 처리 속도가 느려지게 된다.


인라인 태그 안에 블럭 태그가 들어가는 경우 어떻게 표현될지 어려울 수 있는데, 렌더링 시스템과 DOM 의 포함여부는 무관하기 때문에 인라인 태그를 출력하고, 그 아래라인에 블럭태그를 추가한다. 아래 HTML 코드처럼 static 속성과 relative 속성이 만나면 relative 속성을 가진 요소가 항상 static 요소 위에 배치된다. 모든 요소는 기본적으로 position static 으로 렌더링 된다. 

 

<div style="width: 500px;">

  **

  <span>

    HELLO

    <span style="position: relative; top: 50px">WORLD

    <div style="background: tomato;">&nbsp;</div>

    </span>

    !!

    <div style="background: blue;">&nbsp;</div>

  </span>

</div>






Float


- LEFT, RIGHT, NONE, INHERIT

- Inline 요소의 가드로 작동.

- 새로운 Block 요소를 만듦.

- Line Box 공식으로 그림.



example (Normal Flow + Float)

 

<div style="width: 500px;">

<div style="height: 50px; background: tomato"></div>

<div style="width: 200px; height: 150px; float: left; background: rgba(0, 255, 0, 0.5)"></div>

HELLO

<div style="height: 50px; background: skyblue">WORLD</div> 

</div>



위 HTML 코드에서 세번째 <div/> 태그에서 Float 속성을 사용했는데, Float 는 추가적인 BFC 박스를 만드는 역할을 한다. 일단 Float 로 그려지게 되면 Inline 요소는 그안에 배치될 수 없다.



Line Box Model


Baseline 을 찾아 Line Box 를 기준으로 그림을 그린다. Line Box 의 left 와 rigth 의 사이를 기준으로 계산하는데, left 보다 더 left 의 공간이 존재한다면 left를 기준으로 한 빈 공간은 죽은 공간이 된다.



OverFlow


- Float 에 대한 특약사항.

- CSS 2.1 Visual Formatting Model 에 정의.

- VISIBLE, AUTO, HIDDEN, SCROLL, INHERIT



OverFlow-X, -Y


- Recommendation 까지 갔다가 Draft 로 돌아옴 (이런 경우가 비일비재)

- 새로운 스펙이 나오면서 (transform, radio...) 모순점이 발생

VISIBLE, AUTO, HIDDEN, SCROLL, CLIP


HIDDENSCROLL 일 때에는 FLOAT 와 관계가 생김 
새로운 BFC 를 즉시 생성하는데, 새로운 BFC 를 계산할 때 First Line Box Bound 로 인식해서 사용한다. 기존에 Float 계산시에 Block 태그에 대해 새로운 BFC 를 생성 했는데, 'OverFlow: hidden' 을 사용하는 경우 새로운 BFC 를 만들때 Line Box 영역을 고려하여 계산하는 방식으로 작동한다.

원래 Contents 가 클때 Visible 속성이면 박스가 늘어나는데, Line box 에서는 늘어나지 않는다.




POSITION

- STATIC(기본값), RELATIVE(상대값), ABSOLUTE, FIXED

아무리 추상적으로 계산해도 Geometry 계산을 거치면 Fixed Number 인 Offset(고유명사) 으로 바뀌게 된다. Offset 은 참고할 수는 있지만 변경이 불가능한 Readable 속성이다. 브라우저는 효율적 계산을 위해 Geometry 계산을 몰아서 하려 하는데 이때 한번에 묶어서 계산하는 단위를 Frame 이라 부른다. 큐에 계산할 것들을 쌓아놓고 Flush 로 큐를 비우는 작업을 반복하고, 계산이 모두 끝나 큐가 비워지면 그때 Offset 을 구할 수 있다. 우리가 Offset 을 요청할 때마다 큐를 비우고 다시 재계산하기 때문에 Geometry 계산이 끝나기 전의 Offset 조회는 권장하지 않는다.

Offset 을 구하려면 상대적인 위치로 모든 요소들이 저장되어 있기 때문에 일단 계산을 위한 기준점을 찾는 것이 중요한데, 이때 기준점을 Offset Parent 라고 부른다. Offset Parent 를 찾는것은 DOM Parent 를 찾는 계산과는 다르다. Position 이 Fixed 인 경우 Offset Parent 는 존재하지 않고, Root, HTML, BODY, createElement() 같은 것들 역시 Offset Parent 는 존재하지 않는다.(= null) 내가 Position Absolute 이면 나의 Offset Parent 는 Relative 이거나 Absolute 여야만한다.

example 01

 

<div style="width:200px; height:200px; background:yellow; margin:100px;">

<div style="width:100px; height:100px; background:red; position: absolute;"></div>

<div style="width:100px; height:100px; background:blue; position: absolute; left:0;"></div>

</div>



위의 HTML 코드는 아래와 같은 결과를 보여준다.

Position Absolute 의 기본값 Offset 은 (0,0) 이 아니라 DOM 상의 부모를 기준으로 그려진다. 노란색 상자는 빨간상자, 파란 상자의 DOM 상의 부모이고, Static 하기 때문에 기본값 Offset 은 노란상자를 기준으로 계산하게 된다. 단, left 나 top 속성을 주게되면 각각 0 을 기준으로 계산하게 된다. left, top 과 같은 속성은 Offset Parent 에만 적용되고, Static 인 경우에는 무시된다.

(Absolute 인경우에는 Offset Parent 기준으로 계산, Relative 인 경우는 Normal Flow 로 그린 후 계산, Static 인 경우에는 무시)



example 02


<style>

.in {

width: 100px;

height: 100px;

border: 1px dashed #000;

display: inline-block;

}

.abs {

position: absolute;

width: 50px;

height: 50px;

background: tomato;

left: 40px;

top: 40px;

}

.rel {

position: relative;

</style>


<div class="in"></div>

<div class="in"></div>

<div class="in"></div>

<div class="in"></div>

<div class="in"></div>

<div class="in"></div>

<div class="in">

<div class="abs rel"></div>

</div>

<div class="in"></div>

<div class="in"></div>

<div class="in">

<div class="abs rel"></div>

</div>

<div class="in"></div>

<div class="in"></div>

<div class="in"></div>

<div class="in"></div>

<div class="in"></div>

<div class="in">

<div class="abs rel"></div>

</div>

<div class="in"></div>

<div class="in"></div>

<div class="in"></div>

<div class="in"></div> 



Position Absolute 의 부모가 될 수 있는 애들은 Absolute 이거나 Relative 여야만 하기 때문에, 그림을 그리는 위치의 기준점인 Offset Parent 는 DOM 상의 부모가 아니기 때문에 Absolute, Relative 를 찾아 Recursive 한다. Absolute 의 위치는 Static 인 BODY 를 기준으로 하기 때문에 위의 코드에서 각각의 Static 안에 Absolute 를 넣기 위해 컨테이너로써 Relative 를 활용한다.