CSS란?
CSS(Cascading Style Sheets)는 종속형 스타일 시트 언어입니다. *마크업 언어의 스타일을 웹사이트에 표현하는 데 사용합니다. HTML 요소에 선택적으로 스타일을 지정할 수 있습니다.
*마크업언어: 태그로 문서나 데이터 구조를 표시하는 언어
css로 엘리먼트에 float: left 속성을 주면 왼쪽에 배치됩니다. 'left 값을 주면 왼쪽에 배치된다'고 추상적으로 알고는 있지만, 우리는 실제로는 어떻게 배치가 됐는지는 알지 못합니다. 그래서 오늘은 평소에 당연하다고 생각했던 CSS 스타일이 어떤 과정을 거쳐 그려지고 있었는지 알아보려 합니다.
CSS 등장 배경
우리가 보는 화면은 픽셀들로 이루어져 있습니다. 이 화면에 그림을 그리는 시스템을 'Graphics System'이라고 합니다. 이 화면에 박스 그림을 그리려면 x, y 좌표와 width, height를 알고 있어야 합니다. 초기에는 이렇게 정확한 위치와 값으로 그림을 그리는 'Fixed Number' 시스템을 사용했습니다. 이런 시스템은 계산하기는 편하지만 점점 다양해지는 기기 환경에 적용하기 어려워졌습니다.
그래서 고정된 숫자가 주어지면 상대적인 위치를 계산할 수 있게 해주는 abstract calculator가 등장했습니다. 이 abstract calculator는 우리가 익히 알고 있는 %, right, block, inline 와 같은 속성들입니다. 이 속성들은 주어진 값으로 상대적인 위치를 계산해주는 함수이자 메타포입니다. '부모 width에서 자식의 width를 뺀 값에 자식 엘리먼트를 위치시킨다'는 함수를 right이라는 메타포로 표현한 것입니다. 덕분에 우리는 엘리먼트를 배치할 때 하나하나 위치를 계산할 필요가 없어졌습니다.
CSS 렌더링
*브라우저의 렌더링 과정도 그러하듯 대부분의 Rendering System은 크게 두 단계로 나뉩니다.
* 브라우저 렌더링 another-light.tistory.com/46
- geometry calculate: 그림을 그릴 박스의 영역을 나누고 알맞은 위치에 배치
- fragment fill: 각 영역에 그림을 그림
CSS rendering 역시 박스 영역을 배치한 후 그려내는 과정입니다. 이를 위해 고정된 값이 아닌 계산된 값으로 박스 영역을 나누고, 칠하는 방법을 고민했고 그로부터 우리가 지금 알고 있는 CSS 속성들이 나왔습니다.
즉, CSS의 속성을 배운다는 것은 메타포가 어떻게 계산되고 어떻게 그려지는지 배우는 것입니다.
normal flow
normal flow는 css rendering에서 가장 많이 쓰이는 일반적인 배치 과정을 말합니다. normal flow에 속하는 계산 공식으로는 block, inline 2가지가 있습니다. 그 외에도 position 모델에 속하는 static, relative는 normal flow에 관여합니다. (absolute, fixed, inherit 제외)
- Block Formatting Contexts (이하 BFC)
- Inline Formatting Contexts (이하 IFC)
- (relative positioning)
Block/Inline Formatting Contexts
block은 부모의 width만큼 가득 채운 한 줄을 차지합니다. 그래서 block 엘리먼트는 width를 작게 하여 공간이 남아도 다음 줄로 넘어가게 됩니다. 그리고 그 각 줄은 각각의 BFC로 볼 수 있습니다.
inline은 자신의 width만큼 공간을 차지합니다. 다음의 inline 엘리먼트는 이전 inline 엘리먼트들의 width합의 값의 위치하게 됩니다. 만약 그 합이 부모 width를 넘어가면 한 줄을 넘어갑니다. 넘어갈 때는 윗 줄에서 가장 높이가 큰 엘리먼트의 height값에 위치하게 되며 이를 기준으로 baseline이라고 합니다. IFC는 한 줄을 모두 차지하는 BFC가 다음에 오면 IFC가 종료됩니다.
Relative Positioning
relative position의 계산 과정은 이렇습니다. 'normal flow로 static하게 그린 뒤 상대적으로 위치를 이동시킨다.' 즉, 처음에 x, y, width, height를 정한 뒤, 부모로부터 상대적인 위치만 계산하여 이동시킵니다.
네이버 header 부분입니다
css 는 이렇습니다.
// 부모
#header .group_flex {
position: relative;
width: 1130px;
height: 100%;
margin: 0 auto;
padding: 0 30px;
}
// 자식
#header .logo_area {
position: relative;
height: 100%;
}
logo_area 클래스에서 position: relative를 빼면 어떻게 될까요? 부모의 패딩 값을 무시한 채 밖으로 삐져나오게 됩니다. 주목하셔야 할 것은 logo_area 영역의 크기는 relative를 빼기 전이나 뺀 후에도 똑같다는 것입니다. 즉, relative는 먼저 static한 위치 크기를 그린 뒤, 상대적인 위치만 이동시킵니다. 그래서 박스 크기에는 변함이 없습니다.
또한, relative는 다른 static 포지션을 가려버립니다. 하지만 relative끼리는 순서대로 쌓입니다.
#header .group_flex {
background-color: red;
}
#header .logo_area {
background-color: blue;
}
Float
float은 normal flow 외에도 우리가 흔히 박스를 배치하는 데 사용하는 속성입니다.
float은 line box로 그려집니다. float은 다음과 같은 특징이 있습니다.
- float은 새로운 BFC를 생성
- text, inline guard: text, inline은 DOM 구조와 상관없이 float 엘리먼트에 의해 밀려남
- BFC는 float 상관없이 자신의 한 줄을 차지함
- float끼리는 처음 float 엘리먼트의 크기 만큼을 뺀 곳이 다음 float 엘리먼트의 line box(가용 영역)가 됨.
- 그 다음 float은 float:left 보다 더 왼쪽에 위치할 수 없고, float:right보다 더 오른쪽에 위치할 수 없음
이렇게 보니 특징이 많습니다. 예시를 들어가며 보겠습니다.
왼쪽은 float: left, 오른쪽은 float: right입니다. 전체 영역인 div#container의 width는 1190px입니다.
왼쪽의 float: left 영역인 빨간 박스의 너비 750px을 제외한 나머지 440px은 그 다음 float 엘리먼트가 사용할 수 있는 가용 영역이 됩니다(4번째 특징). (네이버에서 float:right 엘리먼트의 width는 350px이었습니다.)
여기에 BFC와 IFC를 추가했습니다. 어떻게 될까요?
BFC는 float과 상관없이 한 줄을 모두 차지하며, IFC인 span 태그는 inline guard에 의해 float 엘리먼트에게 밀려나 가운데에 위치하게 되었습니다.
이번엔 span 태그에 float: left를 주었습니다. float은 왼쪽보다 더 왼쪽에 위치하지 않고, 오른쪽보다 더 오른쪽에 위치하지 않습니다(5번째 특징). span 태그는 왼쪽 섹션을 배치하고 난 후 남은 영역인, 초록색 line box에서 가장 왼쪽인 현재의 위치에 배치됩니다.
overflow
overflow에는 다음과 같은 속성 값들이 있습니다.
:visible, hidden, scroll, inherit, auto
1. auto
일반적인 브라우저에선 auto는 visible과 같습니다. 엘리먼트의 overflow 기본값은 대부분 auto입니다. auto의 계산 공식은 '자식의 크기가 커지면 부모도 같이 커진다'는 것입니다. 자식의 크기가 커지면 부모의 geometry의 크기도 변하게 됩니다.
2. scroll
자식의 geometry가 부모의 geometry를 넘어가면 스크롤바를 만듭니다. 쉽게 말해 부모의 너비가 200이고, 자식의 너비가 300으로 늘어나면 부모에게 가로 스크롤바가 생깁니다.
3. hidden
자식이 부모의 크기를 넘어가면 넘어간 만큼의 자식 엘리먼트를 숨깁니다.
이들 중 hidden, auto 속성을 가질 때, float 속성에 영향을 주게 됩니다. float과 연관이 있을 때 갖는 특징은 다음과 갖습니다.
- 새로운 BFC 생성. 이때, 이전 float 엘리먼트의 라인 박스 영역을 인식해서 생성.
- float의 가드로 인해 밀려난 경우, overflow: auto여도 늘어나지 않음
overflow:hidden 속성의 엘리먼트를 추가했을 때, 마지막 float 엘리먼트의 라인 박스(파란색 박스)를 인식해서 나머지 가용 영역에 생기게 됩니다. 그리고 텍스트가 넘어가는 부분은 짤리게 됩니다.
이제 overflow:auto 속성의 엘리먼트를 추가해보겠습니다. auto는 콘텐츠 크기가 넘어가는 만큼 늘어난다고 했는데 파란색 박스를 보면 hidden과 똑같습니다.
float: right 엘리먼트에 의해 가려진 걸까요? 오른쪽 섹션에 opacity를 줘보겠습니다.
가려진 게 아니었네요! overflow의 특징대로, float의 라인 가드에 의해 밀려난 overflow: auto는 콘텐츠 크기가 박스를 넘어가도 더 이상 커지지 않습니다.
여기까지 클래식한 레이아웃에 대한 것이었습니다.
'개발 이야기 > front-end' 카테고리의 다른 글
Component Pattern | Context API 를 활용하자. (0) | 2021.02.24 |
---|---|
리액트 번들 사이즈 최적화 (0) | 2021.02.24 |
자바스크립트 이벤트 루프와 비동기 콜백 | how does javascript work? (0) | 2021.02.19 |
[Browser] 브라우저가 화면을 그리는 법 Render Tree, layout, paint | Browser Rendering (0) | 2021.02.11 |
[Browser] 브라우저가 화면을 그리는 법#1 파싱 | Browser Rendering - Parsing (0) | 2021.02.09 |