CSS

(코드스피츠) 초보자를 위한 css와 렌더링의 기본개념

출저 : https://www.edwith.org/codespitz-css-rendering/lecture/14646?isDesc=false 

 

[LECTURE] 1 그래픽 시스템 : edwith

- hika Maeng(히카맹)

www.edwith.org

참고내용 : https://coding-farmer.tistory.com/14

 

CSS Rendering - 코드 스피츠 76회차를 보고나서 정리

목차 코드 스피츠라는 유튜브를 보고 나서 여태까지 내가 깊게 공부하지 않았다는 느낌을 받았습니다. 그래서 이제부터라도 깊게 공부하기 위해서 코드 스피츠에 올라온 영상들을 차근 차근 정

coding-farmer.tistory.com

출저 : https://www.youtube.com/watch?v=_o1zsrBkZyg&list=PLBNdLLaRx_rKXwi7MulM6v1UG9JLKWIYS 

 

 

 

01. Graphics System & Normal Flow

01-1. 그래픽 시스템

 

 

그래픽스는 기본적으로 점을 찍는 것부터 생각해 볼 수 있다. 화면 안에 흰색점을 찍었다. 이 점을 왕창 찍는다. 이것이 우리가 보고 있는 모니터이다. 픽셀을 나눠보면 위의 그림처럼 보일 것이다. 

하얀점만 있으니 그림이라고 인식할수가 없어서 위와 같이 색이 들어갔다. (일본 우정국 로고) 어떤 것은 하얀색이고 어떤 것은 빨간색이라는 정보가 보인다. 각 점에 위치와 크기가 보인다. 가장 오른쪽 상단에 있는 붉은색 점을 기준으로 말해보자. 좌상단 0부터 시작해서 height는 1이고 width는 저만큼을 갖는 공간에다가 빨간색을 칠했다라고 말할 수 있다. 

 

>>>> x, y, width, height, color

 

현재 우리가 보고 있는 그래픽스의 근본적인 내용을 보면 x, y(or left, top), width, height, color로 표현할 수 있다. 어떻게 되었든 간에 게임이든, 벡터그래픽이든 이 결과는 점으로 우리눈에 보이게 된다. 

 

방금 보았던  x, y, width, height, left, top... 이것들은 숫자가 확정되어 있다. 0,0 / 1, 100... 고정되어 있는 숫자를 통해서 화면을 구성했다. 우리는 이것을 그래픽스 시스템에서 고정되어진 숫자체계(fixed number)라고 한다. 우리가 알고있는 그래픽스의 가장 원시적인 형태는 fixed number이다. 

 

😲 여기서 문제가 발생한다. 

 

PC 뿐만 아니라 다양한 디바이스들(pad, mobile)이 생겨나면서 PC를 위한 1024px로 width를 고정해버리면 다른 디바이스에 적용할 수 없는 문제점이 발생한다. = 즉, 고정되어진 숫자체계로 만들어진 그래픽스는 다른 환경에 적용할 수 없다.

많은 환경적인 변화가 있다. 해상도 뿐만 아니라 브라우저 창의 크기의 변화, 모바일의 세로/ 가로모드의 변화 등 이러한 다양한 환경변화의 변수에 fixed number체계를 적용할 수가 없다. 

 

옛날에는 이것이 큰 문제가 아니였다. 해당 기기에만 해당하는 맞춤형을 만들면 되었지만 범용성 있는 그래픽스 시스템

을 만들려면 이것이 굉장히 어려워진다. 

 

 

그래서

스크린 사이즈,

크롬 사이즈(여기서 말하는 크롬은 브라우저 크롬이 아니라 윈도우에서 브라우저를 열었을때 기본적으로 사용자에게 제공되는 UI를 Chrome이라고 한다. 예를 들어 스크롤바나 닫기버튼 프레임 등을 의미),

하이라키(hierarchy: 계층화) 등 이러한 것들에 숫자를 대신할 어떠한 메타포를 사용한다. 

 

>> %, left, block, inline, float

 

원래는 고정된 숫자로만 그래픽스를 기술할 수 있었는데 %를 예시로 살펴보면, 나의 부모를 기준으로 나타낸 비율이 %를 의미 즉, 어떠한 환경에서 화면이 그려질 때 환경을 인식해서 숫자로 바뀌게 되는 것 (=%는 공식이자 함수). 이런식으로 숫자체계가 아니라 계산으로 이루어진 체계를 사용하여 (이것은 공식이자 수식) 화면이 그려질 때마다 함수, 식을 돌려서 숫숫자로써 화면에 나타내게 한다. (1단계 숫자체계로 바로 화면에 나타냈던 것을 2단계로 거쳐서 나타내게 하는 것)

 

직접 숫자를 적으면 빠르게 화면에 구현할 수 있지만 그러면 여러환경에 적용할 수가 없기 때문에 숫자대신에 공식을 써주는 것, 이것을 추상화된 계산체계라고 하여 Abstract Calculator (업샛 캐큘레이터)라고 한다. 

 

 

하지만 Abstract Calculator만으로는 위와같은 복잡한 화면을 구현하는게 힘들다. 그렇기 때문에 추상화된 그래픽스 체계를 이어받는 공통점을 가진 애들을 만들어간다. 이것을 'components(컴포넌트)'라고 한다. 

그리고 이러한 components들이 일정한 방식과 규칙으로 구현되어 있다면 이것을 'framework(프레임워크)'라고 한다.

 

components의 가장 대표적인 예는 HTML 

 

우리는 HTML에서 그림을 그리기 위해 그림경로의 JPG 픽셀들을 모두 얻어와서 0,0 은 빨강색, 0,1에는 파랑색 이런식으로 처리하지 않는다. <img src="경로" alt=""> 그냥 이와같은 img태그를 불러와서 경로를 넣기만 한다. 이것이 components 레벨이다. 

 

그런데 HTML 태그들은 공통적인 style들이 존재한다. HTML에 나오는 태그들 하나하나를 components라고 본다면 이 태그들이 공통적으로 먹는 style들이 존재한다. 즉, 공통되어진 시스템하에서 components들이 개발되었다고 볼 수 있다. 그래서 HTML 전체체계를 Framework이라고 볼 수 있다. 

이 개념은 점점더 확장된다. 부트스트랩에 나오는 하나하나를 components라고 본다면 부트스트랩자체는 framwork이고 윈도우에 있는 aplication 하나하나를 components라고 본다면 윈도우 그래픽스 전체는 framwork이라고 볼 수 있다. 

 

computer science에 입문할 때 항상 생각해야 하는 방향이 서양인들은 확정적, 고정적으로 생각하지 않고 '상대적'으로 정의한다. 예를 들어 크롬입장에서 윈도우는 OS이다. 윈도우 입장에서 크롬 브라우저는 응용프로그램이다. 그럼 이것의 시점을 약간 변경해서 CSS, Javascript 입장에서는 어떻게 될까? Javascript는 브라우저 상의 응용프로그램이 되었고 브라우저는 Javascript에 OS같은 녀석이 된 것. 컴퓨터 사이언스에 나오는 모든 것들은 상대적인 개념이다. (부모-자식-손자의 개념이 절대적이지 않듯이)

 

 

 

💡 Graphics(점찍는 방법) System 정리 

▪ Graphics System 발전 과정 : Fixed Number > Abstract Calculator > Components > Framework

▪ Fixed Number : 고정된 숫자체계 
▪ Abstract Calculator : 추상화된 계산 >>> %, left, block, inline, float (함수, 2단계에 걸쳐서 화면구현)
▪ Components : 추상화된 그래픽스 시스템 체계를 이어받는 공통점을 갖고 있는 것들 (상대적 개념)
▪ Framework : 컴포넌트들이 일정한 규칙과 사용방법을 지키는 형태로 구현되어 있는 것 (상대적 개념)

 

 

 

 

 

 

01-2. 랜더링 시스템 (Rendering)

 

위에서 Graphics에 대해서 배워보았다. 그래픽스는 간단하게 말해서 '점찍는 방법'이다. 

하지만 랜더링은 전혀다르다. 랜더링은 그래픽스에서만 사용하는 개념이 아니다. '데이터베이스의 내용은 제이슨으로 랜더링해줘'라는 말도 쓴다. 그럼 랜더링이란 무엇일까? 

 

어떠한 대상이 있으면 내가 원하는 모습으로 다시 것을 모두 다 랜더링이라고 한다. 일반적으로 보다 구체적이고 시각적인 형태로 보여주는 것을 랜더링이라고 부른다. (꼭 시각적일 필요는 없다) 예를 들어서 복잡한 주파수 패턴을 컬러로 이쁘게 나타내는 것 또한 랜더링이라고 한다. 사람이 보다 인식하기 쉽거나 기계가 보다 인식하기 쉽게 하는 것 혹은 우리의 목적에 좀 더 부합하게 바뀌거나 등.. 

 

여기서 말하는 랜더링(Rendering)은 그림을 그리기 위한 데이터를 어떻게 그림으로 바꿔 만들어내냐에 대한 것. 그래픽스가 점찍는 방법에 대해 말했다면 랜더링은 어떤 체계를 통해서 그림을 표현하는가. 그리고 그림을 표현하기 위한 정보는 무엇인가. 

 

 

 

네이버가 있다. 이 네이버의 복잡한 그래픽스를 어떻게 표현해 냈을까? 브라우저, 자바스크립트의 도움도 없이 위의 네이버 화면을 만들라고 하면 어떻게 만들 것인가? 바닥부터..!

 

랜더링 시스템은 그래픽스에서 일반적으로 2단계를 통한다. 

 

 

첫번째 단계는 '박스를 찾는 것'이다. 일단 영역을 나눈다. 땅따먹기를 한다고 생각하면 좋다. 이것을 Geometry(지형) Calculate라고 부른다. 어떻게 영역을 나눌것인지 계산을 한다. 

그러고 나서 색칠을 한다. 색칠하는 과정에서 하나하나 색칠하는 대상을 우리는 Fragment(프레그먼트, 단편/조각)라고 부른다. 그리고 이 과정을 Fragment fill 이라고 한다. 

 

(pixcel을 쓰지 않고 fragment를 쓰는 이유는 pixcel이 중립적인 말이 아니기 때문이다.

일반적으로 핸드폰에서 html에서 viewport를 구현하여 scale을 맞추면 해상도 640으로 떨어져 나온다. 그렇다면 현재 여러분들이 사용하는 핸드폰들이 모두 픽셀값(해상도)이 640으로 떨어져 나올까? 아니다. 훨씬 많다. 4개의 픽셀로 1개의 픽셀을 구현하고 있는 건데 (레티오개념, 공부필요) 여튼 그러하기 때문에 여기서 픽셀은 상대적인 개념이다. 우리는 이것을 '픽셀 레티오'라고 부른다. 그렇기 때문에 중립적인 말이 필요했다. 해상도가 얼마가 되었든간에 )

 

다시 정리하자면 Rendering은 Geometry Calculate > Fragment fill 

브라우저도 동일한 방식이다. 지오매트리 계산을 리플로우(reflow)라고 하고 이 채우는 과정을 리페인팅(repaint)이라고 한다. 

  

 

💡 Redering 방식 : Geometry Calculate(지형지물 계산) > Fragment fill (색칠)

 

 

 

 

 

 

 

01-3. CSS Specifications

앞에서 Graphics와 Redering을 언급한 이유는 지금 배우는 CSS는

 

'어떻게 고정되어져 있는 숫자를 사용하지 않고 계산된 체계로 그래픽을 표현할까?',

'지오매트리 영역을 어떻게 표현할까?',

'색칠을 할 때 어떻게 명령을 내릴까?'

 

에 대한 언어인 것을 명확히 하기 위해서이다. 

즉, 우리는 어떠한 지정된 div영역에 빨간색을 채울려고 하면 div{background-color:red;}라고 명령하였다. 이 말은 내가 땅다먹기한 영역(지오매트리)에 프래그먼트를 빨간색으로 채우라는 소리이다. 

 

추상적인 체계에서 %, px은 그나마 쉽다. 수치로써 눈에 보이기 때문이다. 하지만 right와 같이 부모영역에 대비하여 오른쪽으로 자신을 붙인다 이런말들은 CSS에 수도 없이 존재하고 이러한 메타포들을 정확히 이해하지 못한다면 내가 원하는 레이아웃을 구현해내는 것이 쉽지 않다. 그렇기 때문에 CSS를 배운다는 것은 CSS에 나오는 property 또는 value를 구체적으로 어떤한 방식으로 발현되고 표현되는지 이해하는데에 있다. 

 

 

* CSS는 version이라는 말을 쓰지 않고 level을 사용 

 

웹이라는 것은 나중에 발현되는 시스템이기 때문에 기존에 존재했던 학문들을 많이 받아들인다. 그래서 웹에서 있는 CSS rendering 시스템은 수많은 시스템들을 엄청 받아들였고 지금 현재도 계속적으로 받아들이고 있다. 

 

> 그렇기 때문에 체계가 굉장히 난잡 + 복잡 + 일관성이 없다. 

어떤 부분은 이러한 이론에 의해서 만들어져있고 어떠한 방법은 이러한 관념적인 계산방법을 쓰는 등 체계가 한두개가 존재하는 것이 아니다. 그러하면 이러한 복잡한 체계의 사양서를 어떻게 관리하는가? 

 

기본적으로 이것이 맞는 구현인가? 틀린구현인가?라고 판단하는 기준은 '사양서'이다. 브라우저에서 작동하고 있지 않더라도 사양서를 볼줄 알아야한다. 표준이 무엇인지 알아야지 표준대로 구현하고 나머지를 고칠것이기 때문이다. 

 


 

01. CSS leve 1

CSS는 최초에 오페라 브라우저를 만든 이안힉스가 W3C에게 제안을 하였다. 

"HTML 좋긴한데 HTML자체내에 그림과 관련된 것들을 다 집어넣었더니 너무 복잡해서 관리하기가 힘들어 그러니깐 기존에 있는 Graphics에 있는 것들을 차용해와서 CSS라는 것을 만들면 어떨까?" ----- (CSS level1)

 

level1에서의 css는 고작 사양이 A4 한장짜리였다. 할 수 있는 것이 별로 없다. 

 

02. CSS level 2

이때부터 여러개발 회사들에서 CSS에 달려들기 시작.

"우리 이런 아이디어가 있어 집어넣자!!", "우린 이런거 넣었음 좋겠어!"

 

CSS level2에서는 MS i4가 세상을 지배하고 있던 시절이여서 이때 W3C에 있는 스펙들은 다 MS에서 제안한것들이 많다. i6가 완벽하게 구현되는 것이 CSS level2이다. 

 

 

03. CSS level2 + Module

그런데 level2에서 하나 재미있는 것이 나타난다. 

"야 CSS는 그림에 대한 건데 그림에 대한 것을 하나의 스펙으로 관리하는 것은 무리인거 아니야?" 

→ "그래서 CSS 스펙안에 관심분야별로 모듈이라는 시스템을 넣어서 사양을 모듈별로 관리하자" 아이디어 제창

 

윈도우에 있는 랜더링 시스템, Mac에 있는 랜더링 시스템.... 오만가지가 존재 >> 단일관리하는 것이 어려워짐 >> 그래서 사양을 따로따로 떼어내서 관리하자는 아이디어였음 그것이 바로 모듈

이때 CSS level2가 발표되면서 level2에 있는 각종 사양들이 모듈화 되어 있음 

 

 

04. CSS level 2.1 (Include level 3 module)

그러면서 CSS level2.1이 발표된다. 레벨 2.1을 기준으로 css에 있는 모든 모듈들이 모두 딱 2로 고정되었다. 

그런데 여기서 이상한 일이 생겼다. 어떤 분야들은 너무 열심히 연구해서 남들은 2>2.1로 가는 동안 모듈을 3로 발표하는 일이 발생한다. 표준사양위원회에서 이것을 나중에 깨달았다. 어떤 스펙은 굉장히 활발하게 연구를 해서 버전업이 되었고 어떤 것들은 더이상 레벨이 올라갈 일이 없겠구나하는 것 말이다. 

 

> 그렇다면 CSS level3이란 것은 나올 수 있을까?  NO

 

어떤 graphics system은 너무 고전이라서 확정적으로 업그레이드 될 일이 없고 어떤 것들을 발전할 가능성이 있어 계속해서 업데이트되고 있는 상황인 것이다. 

= 즉, CSS 2.1 이후로 CSS3으로 가는게 불가능하다는 것을 깨달았다. 

 

우리가 흔히 부르는 css3는 무엇이다? css level 2.1에 포함된 module중 level3를 모아서 css3라고 부를 뿐이지 공식문서에 css3는 존재하지 않는다. 

 

 

05. Module level 

이후의 체계는 Module level로 바뀐다. CSS 통합 레벨이라는 것은 존재하지 않고 모듈레벨이라는 것들이 존재해서 새로 태어났다. transform / compositing / effect / flex / grid / masking / translate...  이런것들은 css3,4가 아니라 module level1  이라고 말한다. 

 


 

>> CSS의 세계는 module들이 끊임없이 탄생하고 각 모듈들이 나름대로 업데이트가 되고 있다. 지금 W3C에 들어가서 확인해보면 어떤 것들은 level4로 제안되고 있고 어떤것들은 여전히 2로 머무르고 있고 제각각이다. 

 

CSS가 난잡하고 복잡하고 각 브라우저마다 동작하는 것이 틀린 것은 MS가 일을 하지 않아서가 아니다. CSS탄생자체가 위와같기 때문에 브라우저들이 각 최신 CSS 모듈들을 따라가기가 힘든 것이다. (하나의 공통된 팀으로써 진행되고 있는 것이 아니기 때문에) 즉, 브라우저가 transform을 지원해 하고 끝나는 것이 아니라 level 몇을 지원하고 있는지를 사양서에서 확인해야한다. 

 

i8에서 사용할 수 있는 selcetor의 스펙은 levle1 이고 i11에서 사용할수 있는 스펙은 level2이다.

 

 

 

 

W3C가 영향력을 많이 가지고 있던 시대에는 스티브잡스가 아이폰을 만들기 전이다. 아이폰이 탄생하면서 MS의 영향력이 굉장히 낮아졌고 Google, Apple의 영향력이 강화되었다. 그러면서 기존에 MS의 단체 W3C에 새로운 신흥강자들이 반발을 많이 한다. 그러면서 W3C도 많은 것을 내려놓게 된다. 예전에는 W3C에서 먼저 권고해야지 브라우저에 내놓을 수 있게 통제를 하였는데 그렇지 않게 되었다. 현재 크롬에 있는 새로운 기능들은 W3C의 권고안이 아니다. 대부분 드래프트(draft, 초안)이다. (W3C에서 중앙통제하던 그 힘이 거의 없는 상태)

그래서 이러한 점을 W3C에서도 인정하여 W3C community and Business Groups이라는 것을 운영하기 시작했다. 이 산하에 있는 커뮤니티활동을 공식적인 활동으로 인정한다는 의미. 그래서 구글, 삼성, 애플 이런애들이 이곳에 모여서 그룹하나 만들어서 자신들이 만들고 싶었던 것들을 사양 맞춰서 삼성브라우저에 넣고 구글 브라우저에 넣고 한다. 이 중에서 CSS의 영향력이 있는 그룹(단체)들이 있는데 그 그룹중에 WICG, RICG가 있다. (RICG가 WICG한테 거의 먹혔는데 google 주 멤버이기 때문)

 

>> 그렇기 때문에 이젠 CSS를 이해할려면 W3C의 스펙으로만으로는 한계가 있다. 다양한 어용단체들이 속해있는 그룹들이 만들어낸 사양들이 실제 브라우저에 반영되고 있기 때문이다.(CSS 표준을 지정하는 방식이 변화한 것을 설명하였다)

 

 

 


 

여기까지 기본적인 CSS의 베이스가 될 배경지식이었다. 

 

 

01-4. Normal Flow

 

 

 

Normal Flow (고유명사)

일반명사 아니다. CSS에 공식적으로 나오는 고유명사이다. 

 

더보기

서양학문의 두번째 문제점이 여기서 나타난다. 

첫번째 문제점 '확정적으로 정의하지 않고 상대적으로 정의'한다고 하였다. 

두번째 문제점은 고유명사를 일반명사로 정의해버린다. 

 

대표적이 도메인(domain)이 있다. 이것을 일반인들에게 물으면 '마당, 영역'으로 해석한다. 

IT에서 도메인은 고유명사로써 IP를 의미한다. 

프로토콜은 '의정서, 합의서'라는 의미가 존재하지만 IT에서는 고유명사로 존재한다. 

 

그렇기 때문에 Normal Flow는 한국말로 해석이 되지 않는다. 고유명사이기 때문이다. 

 

 

CSS level 2.1에 보면 Visual Formatting Model이라는 문서가 있다. 어떻게 화면에 보이는 것들을 포맷, 모델링 할 것인가하는 문서. 여기에서 보면 positioning schemes(포지셔닝 스키마), normal flow라는 단어가 나온다. 

 

Position이 무엇이냐? 

Graphics에서 추상적인 개념체계를 배웠는데 position은 어떤 geometry에 left, top(x,y)을 결정할 때 사용하는 추상적인 의미체계(system)이다. 여기에는 static, relative, absolute, fixed, inherit 모델이 있다. (이것들이 계산 공식으로 보여야한다)

 

근데 Normal Flow는 position: static; or relative;일때만 적용된다. 

 

Normal Flow는 두가지로 설명(두가지 계산공식)이 된다.

1) Block Formatting Contexts (BFC)

2) Inline Formatting Contexts (IFC)

3) Relative Positioning

 

 

 

 

 

01-5. Normal Flow : BFC 

 

 

block : 부모의 가로길이를 가득 채운 한 줄 (가로를 다 먹어, 부모만큼)

 

즉, BFC는 한줄을 다 먹을 때 어떤식으로 계산되어서 한줄을 다 먹는지에 대한 이야기인것이고 그렇기 때문에 x는 언제나 0이다. 그러므로 BFC에서 고려해야할 점은 단 하나, 다음번  block요소가 나올때 그 다음의 y자리는 어딘가이다. (첫번재 block context의 height값이 두번째 block요소가 나타나는 y값)

= 이러한 계산방법이 BFC

 

inline : 한줄을 다 먹지 않고 나의 content 크기만큼 차지한다. 

 

그렇기 때문에 두번째 inline요소의 x값은 첫번째 inline요소의 x값(width)만큼의 값을 가진다. 브라우저의 도움없이 레이아웃을 짠다고 하면 이런것들을 이런식으로 계산해야한다. 세번째 inline요소는 첫번째 width+ 두번째 width값을 더한 만큼의 x 위치값을 가지게 된다. 그런데 inline요소들의 width값의 합이 부모의 width값을 넘어가게 되면 다음 줄로 내려간다. 그러면 얼마만큼 내려가지? 지금 앞에서 존재했던 inline요소들 중에 height가 가장 큰 inlline요소의 크기만큼의 y위치값을 가지게 된다. (이 계산하는 방식이 익숙하지 않겠지만 우리가 컴퓨터라고 생각해보자. 이 원리를 알아야한다.) 

 

 

 

우와 같은 html 구조가 있다면 아래처럼 나타날것이다. 우리는 평소 div 박스를 만들고 당연하게 생각해왔던 구조이지만 좀더 구체적으로 뜯어서 살펴보자. 첫번째 div(붉은색)에 width:500px;값을 주어서 프레그먼트영역만 저 만큼 차지하고 있긴 하지만 애초에 block요소는 부모의 가로길이를 가득 채운다고 했다. 그렇기 때문에 실제적으로 저만큼 모든 가로를 차지하고 있기 때문에 다른 요소가 위로 올라올 수 없다. 

 

 

 

 

 

01-6. Normal Flow : IFC 

 

 

그럼 이번에는 IFC를 살펴보자. 위와 같은 html구조가 있다고 했을 때 실제적으로 A처럼 나타난다. IFC, inline인데 왜 부모요소보다 큼에도 불구하고 끊어져서 나타나지 않고 이런식으로 나타나는 걸까? 

 

왜냐하면 컴퓨터는 끊어쓰지 않으면 저 뭉텅이를 하나의 IFC 섹션으로 보기 때문이다. enter가 되었든 space가 되었든 공백을 주는 순간 span 태그처럼 하나의 inline요소가 되기 때문에 B에서는 따로따로 나타나게 되지만 A에서는 공백이 없기 때문에 하나의 IFC섹션으로 여겨져서 저렇게 나타나는 것이다. 

 

그래서 A를 B처럼 나타내고 싶다면 1) 공백문자를 삽입하거나 2) wordbreak를 줘야한다. HTML에서는 공백이 없는 연속된 문자열은 하나의 inline으로 본다. 그렇기 때문에 A에서 뚫고 나온다. 

워드브레이크를 주면 문자 하나하나를 inline으로 보면서 하나하나  geometry로 잡기 때문에 느려진다. 

 

 

 

 

01-7. Normal Flow : BFC + IFC 

 

 

이제 BFC, IFC를 좀더 응용해서 생각해보자 

위와 같은 구조가 있다고 하자. width: 500px인 div가 있다. 이것은 block요소이다. 그 안의 hello는 inline이다. 

span에 있는 world 또한 inline이다. 

그런데 span안에 div라는 block요소가 존재한다. 그렇다면 이건 어떻게 작용할 것인가? 

 

😲 span은 inline요소이니깐 span 옆에 !!가 붙어야 하는건가? 아닌가? span은 inline이지만 div라는  block때문에 쪼개져서 그 다음에 !!가 붙는 걸까...?

 

>> 이게 어려운 이유는 rendering system에 대한 이해가 없기 때문이다.

DOM의 포함관계와 Rendering의 포함관계는 다르다. Rendering은 BFC, IFC로 나뉜다고 하였다. DOM에서는 span안에 div가 존재할지 몰라도 그림을 그리는 브라우저는 BFC(div) > IFC(hello) > IFC(world) > BFC(div) > IFC(!!) 식으로 보이게 된다. 

 

 

 

그래서 이와같이 결과가 나타난다. 

tag의 구조와 rendering의 구조가 일치하는 것이 아니다. 

 

 

 

 

 

 

Rendering순서 : BFC(div) > IFC(**) > IFC(hello) > IFC(world) > BFC(div) > IFC(!!) > BFC(div) > IFC(**)

** HELLO WORLD

[  레드 div                             ]

!!

[  블루 div                             ]

** 

 

 

 

 

 

relative는 static으로 위치시켰는데 상대적으로 이동시킨다고 이해하면 된다. 

 

 

왼쪽이 static / 오른쪽이 relative로 아래로 내려간 형태

 

WORLD하고 빨간색만 아래로 내려간다. 다른것은 그 위치에 존재한다. 

그런데 position: static;과 position: relative;가 섞여 있으면 무조건 relative가 static; 위로 올라온다. 그렇기 때문에 위의 화면처럼 WORLD와 빨간박스만 **과 파란박스를 일부가리면서 위로 올라온다. 

relative 때문에 전체 박스의 크기나 높이가 변하지는 않는다. geometry에서는 static으로 계산이 이미 끝났고 그림 화면에서만 오른쪽처럼 나타나는 것

 

여기까지가 모두 Normal Flow에 관한 이야기였다.

왜 노말플로우라는 말을 붙였을까? 브라우저에서 가장 많이 쓰이는 공식(메타포, 로직)이 이것이기 때문이다. 

fixed, absolute 를 주면 더이상 노말플로우가 작동하지 않게 되어서 반드시 width를 주지 않으면 이상한 레이아웃이 만들어진다. 

 

 

 

 

 

01-8. Float

 

 

float는 BFC, IFC로 이야기하지 않는다. Line Box라는 공식으로 이야기한다. 

여러분은 이제 이러한 추상적인 개념들이 '공식'으로 보여야한다. CSS를 공부한다는 것은 이러한 공식들을 이해하는 것이다. 다시 정리하자면 float는 linebox로 그려지는 것, normal flow는 IFC, BFC, relative 원리로 그려지는 것이다. 

 

float를 이해할려면 Linebox와 Inline Guard에 대해서 알아야한다. 

 

그렇다면  Linebox 공식을 공부해보자. 

 

 

 

01-9. Float : Line Box

 

 

먼저 간단하게 BFC와 Float를 결합해보자. 

첫번째 red박스 div를 만들었다. BFC 지오매트리 영역이 설정되었다. 그리고 다음 div박슬르 보면 float 속성을 부여하였다. float라는 속성을 주는 순간 기존에 있던 BFC영역을 파기하고 새로운 BFC영역을 만든다. 

= float 속성을 부여하는 순간 rendering은 새로운 BFC영역으로 인식한다. (생성된다)

>> float를 넣을 때 마다 geometry 계산이 까다로워진다. 

 

세번째 div박스는 일반적인 normal flow로써 float때문에 만들어진 BFC영역에 그려지게 된다. 

그런데 float는 떠있는다고 하였다. 그래서 초록색 박스(두번째 div)가 떠있는 상태이다. 

 

💡 float는 새로운 BFC 영역을 만든다.

 

 

01-10. Float : Inline Guard

 

 

이번에는 Inline Guard 특성에 대해서 배워보자. 

위에서 사용했던 구조와 동일하지만 Hello, World, !!인 inline요소가 추가가 되었다. 이 구조는 어떠하게 나타나겠는가 ?

위의 그림처럼 그려지는데 왜 저렇게 그려지는 걸까? 

 

div 박스들은 위에서 말한 원리대로 그려진다. 그런데 float 박스 뒤에 HELLO inline이 추가되었다. 세번째 div박스(skyblue 색상)이 시작되기 전에 그래서 빈 공간에 HELLO가 들어가게 된다. 원래라면 초록색 제일 상단쪽에 HELLO 가 그려져야 할것이다. 그런데 Float는 inline의 가드로 작동하기 때문에 바깥쪽에 그려지게 된다. 

 

그런데 float는 inline의 가드로 작동하지 block의 가드로 작동하지 않는다. 그렇기 때문에 두번째 div박스는 부모 전체의 가로 비율을 다 차지하면서 겹쳐져서 위와 같이 나타나게 되는 것이다. 하지만 두번째 div박스 안에 있는 World는 inline요소이기 때문에 가드로 작동하여 가장 왼쪽이 아닌 초록색(float)의 바깥영역쪽에 표시되게 된다. 

 

 

💡 float는 inline요소의 guard로 작동하게 된다. 

 

 

 

 

float는 float속성이 부여될때 rendering BFC 새로운 영역으로 인식되고 inline요소가 있을 때는 guard로 작동한다는 것을 간단히 살펴보았다. 그렇다면 좀더 복잡한 레이아웃의 경우 어떠한 식으로 나타나게 될까? 

 

아래에 width값이 다른 div박스들이 float가 left, right로 차례대로 들어가있는 레이아웃 구조가 있다. (마지막은 float를 주지 않았다). 여기에서 class의 의미는 float를 주었다는 표시이다. 

이 구조는 어떠한 식으로 나타나게 될 것인가? 

 

cf) 

.left{float:left; background:green; color:#fff}
.right{float:right; background:red; color:#fff}

 

 

1~7 + div 까지 순서대로 그려보자. 

 

1번 박스는 float, left 속성이 들어가있다. 전체 박스는 500px인데 1박스는 width가 200px이니 위와 같이 나타날 것이다.

저 노란색 점선으로 표시된 것이 첫번째 1번 div박스가 사용할 수 있는 float의 영역(line box)이다. left로 설정되어 있으니 line box의 가장 왼쪽에 붙을 것이다. 

(line box에서 오직 신경쓰는 것은 float 가 있으냐 없느냐이다. 이것만 신경쓰자)

 

 

두번째 박스는 어떻게 그려질것인가?

width: 50px에 height:150px(div_1과 높이 동일)하고 float, right 속성이 부여되어 있는데 오른쪽에 아무런 방해될 요소가 없으니 가장 오른쪽에 붙을 것이다. 여기서 중요한 것은 Line box의 영역이다. 

div_1에서는 그 어떠한 float요소를 가진 박스가 없었기 때문에 전체 div의 500px 영역모두가 linebox의 영역이었다. 하지만 div_2에서는 이미 div_1이라고 width:200px, float 요소를 가진 박스가 만들어져 있기 때문에 linebox의 영역이 위와 같이 전체가 아니라 500px-200px인 나머지 300px만을 가지고 그 영역안에서 가장 오른쪽에 div_2가 붙게 된다. 

 

 

div_1과 div_2를 통해 어떤식으로 그려지는 보았다. 이젠 BFC 영역안에 float 두개가 이미 만들어져있는 상태이다. div_3을 보면 width:50px, height:100px인 박스이다. linebox는 첫번째, 두번째 float 요소를 제외한 나머지 영역으로 잡히면서 위와 같이 그려진다. 

(linebox는 가로만 보는 것이 아니라 세로도 봐야한다. 가로와 세로의 가용한 영역을 봐야한다는 말이다.)

 

 

div_4의 경우 float,left이며 width:150px, height:50px인 박스이다. 아직 1,2,3의 width를 제외하고도 200px의 가용할 범위가 있으니 linebox가 위와같이 형성되고 div_4는 위와같이 나타날 것이다. 

 

div_5를 보자. 어떻게 들어가겠는가? 

<div class="right" style="width:150px; height:70px">5</div>

라고 현재 되어있는데 이제 1,2,3,4가 들어가고 남은 linebox의 영역은 50px밖에 남지 않았다. 하지만 div_5는 150px의 너비를 가지고 있다. 이런식으로 더이상 남아있는 linebox의 영역안에 float의 요소가 들어갈 자리가 없다면 마지막으로 만들어진 linebox의 경계의 가장 하단면(바닥면)을 기준(바운드라인)으로 빈 공간이 linebox의 영역이 된다. 

 

 

그러면 div_5는 위와 같이 들어가게 된다. 

그런데 이기서 linebox의 height가 70px이었기 때문에 div_3의 길이의 영역에서 더 벗어나면서 옆에 빈공간이 생긴것을 확인할 수 있다. (div_5의 오른쪽이자 div_3의 아래부분 영역) 그런데 linebox에서는 가장 오른쪽 영역보다 더 오른쪽을 인식하지 못한다(왼쪽또한 동일). 즉 다시 말해 

 

 

linebox는 노란색 선으로 표시된 오른쪽 영역을 인지하지 못한다는 소리이다. (죽은 공간, 없는 공간)

 

 

 

div_6는 div_5에서 봤던 것과 같은 원리로 위에처럼 그려지게 된다. 

 

div_7의 경우 아래와 같다. 

<div class="left" style="width:150px; height:50px">7</div>

너비 150px이 들어갈 linebox 영역이 남아있지 않음으로 베이스라인을 기준으로 가장 left에 div_7이 붙어 위와 같이 그려진다. 

 

 

마지막으로 float속성이 없는 일반 div_ABC를 만들었다. 

유일한 normal flow요소이기 때문에 첫번째 BFC영역에 딱 그려진다. 

float는 inline은 가드하지만 block은 가드하지 않는다. 그렇기 때문에 block으로써 박스는 전체가 다 그려지지만 ABC는 inline이기 때문에 남은 공간인 저곳에 그려지게 된다. 

 

그렇다면 inline 영역이 길어져서 아래와 같은 코드를 짜게 된다면 어떻게 그려질까 ?

 

 

 

이런식으로 나타나게 된다. 

 

 

노란색으로 표시된 공간들은 linebox의 left를 넘어섰거나 right를 넘어선 공간이기 때문에 죽은 공간으로 들어갈 수 없는 영역이 되었고 회색영역들로 inline들이 들어갈 것이다. 

 

아래의 코드로 다시한번 연습해보자. 

 

 

 

이제 우리는 베이스라인들을 인식할 수 있고 왜 우리눈에는 남는 공간이라도 보이는 부분을 컴퓨터는 인식할 수 없는지 알게 되었다. 

 

 

 

 

 

01-11. overflow : hidden; / scroll;

 

여기서 끝나면 좋겠지만 😂 아직 끝나지 않았다. 

float에 대한 특약사항들이 있다. overflow에 나온다. 

 

css 2.1 visual formatting model을 보면 overflow에 대한 정의가 나온다. 

 

 

overflow: auto;(default) - 내부에 있는 요소의 크기가 커지만 부모도 같이 커진다. 즉, geometry의 크기가 직접적으로 바뀐다. overflow: visible; - visible이 auto이다. 일반적인 브라우저가 visible로 설정되어 있다. (예전에는 이것이 나뉘어져 있었던 적이 있어서 auto, visible 속성값이 두가지가 존재)

 

overflow: scroll; - 부모의 크기를 벗어나는 컨텐츠가 발생하면 바를 만든다. 

overflow: hidden; - 부모의 크기를 벗어나는 컨텐츠가 발생하면 내용을 잘라버린다. 

 

 

overflow -x, -y에 대한 것도 있다. 이것은 한꺼번에 관리하지 않고 x축, y축을 따로 관리하는 스펙이다. 굉장히 오래된 스펙처럼 보이지만 놀랍게도 아직까지 draft(초안)이다. 왜? 원래 recommendation(권고안)까지 갔다가 다시 draft(초안)가 된 케이스인데 사실 이러한 일은 css에서 비일비재하다. recommendation일 때는 overflow-x,y에 대한 transform 계산이 필요없었지만 transform이 생겨난 이후로 문제점이 발생, 다시 그래서 draft가 된 케이스이다. 이것이 새로운 CSS가 나오면서 기존의 CSS에 영향을 끼친 대표적인 사례이다. (그지같은 CSS 표준...)

 

 

overflow에는 text-overflow라는 속성 또한 존재한다. (이클립스 - 점점 텍스트를 표시하는 것)

 

 

 

overflow 속성은 위에서 보는 것과 같이 저렇게 다양한 것들이 존재하지만 

hidden, scroll일때에만 float와 관련있다. 

 

왜냐하면 overflow가 hidden이거나 scroll 일때는 이 값을 가지는 요소로부터 새로운 BFC를 만든다는 규약이 있다. 이 규약때문에 이 속성이 hidden과 scroll의 값을 가질때에만 float와 연관이 있게 된다. float와 직접적인 관계는 아니지만 이것이 영향을 끼쳐서 첫번째 Line box의 바운더를 이용해서 BFC영역을 만든다는 것이다. 

그냥 새로운 BFC를 만든다면 float와 연관이 없겠지만 overflow:hidden; scroll;일때는 새로운 BFC 영역을 만드는데 첫번째 linebox의 바운드를 이용하여 새로운 BFC영역을 만든다. 

 

이게 도대체 뭔 소리야? 😵 아래의 예제를 보자 

 

 

  <div style="width: 500px;">
    <div class="left" style="width: 200px; height: 150px;">1</div>
    <div class="right" style="width: 50px; height: 150px;">2</div>
    <div class="right" style="width: 50px; height: 100px;">3</div>
    <div class="left" style="width: 150px; height: 50px;">4</div>
    <div class="right" style="width: 150px; height: 70px;">5</div>
    <div class="left" style="width: 150px; height: 50px;">6</div>
    <div class="left" style="width: 150px; height: 50px;">7</div>
    <div style="height: 40px; background-color: red;">A</div>
  </div>

 

위의 코드는 아래처럼 표현될 것이다. 

 

 

 

참고) 

 

    .left{float: left; background-color: rgba(154, 205, 50, 0.7);} 
    .right{float: right; background-color: rgba(135, 206, 235, 0.7);}

 

 

float들은 block요소를 가드하지 않으니 마지막 div(A)는 부모만큼의 가로길이 500px값을 가지게 되지만 안에 들어있는 inline요소인 A는 float가 가드하여 float가 없는 위치에 있을 것이다. 

 

위의 코드의 마지막 div(A)에 overflow:hidden;을 추가하게 되면 첫번째 linebox의 바운드에 새로운 BFC 영역을 만들것이고 이것은 아래와 같게 나타나게 된다. 

 

 

  <div style="width: 500px;">
    <div class="left" style="width: 200px; height: 150px;">1</div>
    <div class="right" style="width: 50px; height: 150px;">2</div>
    <div class="right" style="width: 50px; height: 100px;">3</div>
    <div class="left" style="width: 150px; height: 50px;">4</div>
    <div class="right" style="width: 150px; height: 70px;">5</div>
    <div class="left" style="width: 150px; height: 50px;">6</div>
    <div class="left" style="width: 150px; height: 50px;">7</div>
    <div style="height: 40px; overflow: hidden; background-color: red;">A</div>
  </div>

 

 

BFC는 부모영역만큼 width를 가진다 그런데 여기서 overflow:hidden;(or scroll)은 linebox의 bound만큼을 인식한다는 규정또한 들어가있다. 위의 코드에서는 빨간색 박스가 전체를 다 차지했지만 위의 규정 두가지때문에 위에처럼 나타난다. 

 

 

이것을 이용하여 여러가지 것들을 해볼 수 있다. 

위의 코드를 그대로 두고 이어서 만들어보자. 

 

위의 코드는 overflow:hidden;에 의해서 새로운 BFC를 형성 위와같은 구조가 완성된다.

 

추가된 세번째 div의 경우 overflow:hidden; 속성이 없기 때문에 normal flow에 의해서 위치하게 된다. 

 

 

 

 

여태까지 한 예제를 전체적으로 한번 살펴보자 

 

 

앞에서 넣었던 normal flow의 div박스안의 ABC1 ABC2 등이 기억나는가? 

그런데 default값이 overflow: visible;이라고 하였다. 그렇다면 안의 컨텐츠만큼 부모또한 늘어나야하는게 맞는데 이것은 왜 늘어나지 않고 저만큼의 영역만 붉은색으로 자리잡고 있을까? inline요소인 글자들은 흘러넘쳐서 저렇게 위치하고 있는데?

 

>> 결론부터 말하자면 linebox때문에 inline요소가 밀려서 커질때는 (guard작동으로 늘어날때는) 저 박스가 overflow: visible;이라고 하여도 늘어나지 않는다. 실체는 저 빨간박스에서 끝났다. (pixcel로 찍혀져는 있지만 geometry로 영역을 차지하고 있지 않다.)

 

그렇기 때문에 ABCB글자와 뒤에 우리가 만든 예제가 겹쳐져서 보이는 이유다. 

 

 

 

See the Pen CSS Rendering : normal flow + float + overflow by hansol (@hansol_hodu) on CodePen.

 

 

 

왜 D는 쌤이랑 다른식으로 나타나지...? 

 

 

 

 

 

여기까지를 CSS의 고전 레이아웃이라고 부른다. grid, flex가 오기 전의 레이아웃 시스템을 말한다. 

모든 브라우저가 제공하는 레이아웃은 위의 레이아웃이기 때문에 확실히 공부해야한다.