HTML 태그는 줄바꿈 가능 여부에 따라 block
요소와 inline
요소로 구분이 가능하다. 그리고 이러한 요소의 특징을 CSS의 display
속성으로 제어할 수 있다. 그렇다면 display
속성은 무엇이고, 어떤 값을 설정할 수 있을까? 특히 block
과 inline
요소의 차이에 주목하여 글을 작성해보고자 한다.
먼저 display
속성이 무엇인지 간단하게 살펴보면, display
는 말 그대로 요소를 어떻게 보여줄지 결정하는 속성이다. 보여주는 방식을 결정한다는 것은 곧 HTML 요소의 레이아웃 배치 방식에 관여한다는 의미이기도 하다. 즉 display
속성의 값을 어떻게 설정하는지에 따라 페이지의 레이아웃이 달라지기 때문에, display
속성값의 특징을 정확히 이해할 필요가 있다.
공식 문서에서는 display
속성의 값을 6가지 기준으로 다양하게 분류하고 있다. 하지만 이 글에서는 그 중에서도 요소의 외부에 관여하는지, 내부에 관여하는지에 초점을 맞춰 살펴보고자 한다.
💡 외부 디스플레이 유형
:
block
,inline
💡 내부 디스플레이 유형
:
flex
,grid
,flow
,flow-root
위에서 간단하게 살펴본 바와 같이 display
속성의 값은 관여하는 곳이 요소의 외부인지, 내부인지를 기준으로 외부 디스플레이 유형과 내부 디스플레이 유형으로 구분할 수 있다.
먼저 외부 디스플레이 유형은 요소가 플로우 레이아웃에 참여하는 방법에 관여한다. 여기서의 플로우 레이아웃을 normal flow라고 부르기도 한다. 이 글에서는 보다 직관적인 normal flow를 사용하여 설명하고자 한다.
normal flow를 직역하면 '일반적인 흐름'인데, 이 흐름은 레이아웃의 변화가 있기 전까지 페이지 안의 block
요소와 inline
요소가 보여지는 방식을 의미한다. 이를 정리하면 다음과 같다.
💡
block
: 기본적으로 부모 요소의 가로 영역을 모두 채움
:block
요소 다음에 등장하는 태그는 줄 바꿈이 됨, 문단과 비슷한 역할
:width
,height
값 적용 가능
ex)div
,p
,h1
,h2
,li
...
💡
inline
:
block
요소와 달리 줄 바꿈이 되지 않음
:inline
요소 뒤에 나오는inline
요소는 부모 요소의width
값을 넘기 전까지 계속 나열됨
:width
,height
값이 적용되지 않기 때문에 콘텐츠의 크기가 곧 inline 요소의width
,height
ex)span
,b
,i
,a
...
위의 요약을 바탕으로 CSS의 normal flow에는 block
요소처럼 위에서 아래로 배치하는 방식과 inline
요소처럼 왼쪽에서 오른쪽으로 배치하는 방식이 있음을 알 수 있다. 지금부터 이를 구체적으로 살펴보고자 한다.
normal flow의 배치 방식을 살펴보기 전에, 어떤 원리로 배치하는지 먼저 알 필요가 있다. normal flow의 배치는 요소의 left 값과 top 값을 계산함으로써 이루어진다. 즉 요소가 왼쪽으로부터 얼마나 떨어져 있는지, 위쪽으로부터 얼마나 떨어져 있는지를 파악한 후 레이아웃을 배치하는 것이다.
앞서 block
요소와 inline
요소를 살펴보면서 normal flow에 두 가지의 배치 방식이 있음을 확인했다. 구체적으로 block
요소처럼 위에서 아래 방향으로 배치하는 방식, 혹은 배치하면서 암묵적으로 생성되는 block
레벨 레이아웃을 BFC(Block Formatting Context)라고 한다. 반면 inline
요소처럼 왼쪽에서 오른쪽 방향으로 배치하는 방식, 혹은 배치하면서 암묵적으로 생성되는 inline
레벨 레이아웃을 IFC(Inline Formatting Context)라고 한다.
정리하면 BFC는 해당 요소가 부모 요소의 가로 영역을 꽉 채워서 차지할 때의 left 값과 top 값을 계산하는 방식이고, IFC는 해당 요소가 콘텐츠 영역만큼 차지할 때의 left 값과 top 값을 계산하는 방식이다. normal flow는 block
요소를 배치할 때 BFC를 유지하다가 inline
요소를 만나면 IFC로 변경하여 배치하게 된다.
위의 그림을 통해 BFC와 IFC를 좀 더 자세하게 살펴보자. 먼저 div
는 block
요소이므로 2개의 div
를 배치할 때까지 normal flow는 BFC를 따르게 된다. 구체적으로 left, top 값을 어떻게 계산하는지 살펴보면, 첫 번째 div
의 경우 block
요소이므로 left 값은 부모 요소의 left 값과 동일하다. top의 값은 위에 다른 block
요소가 없기 때문에 당연히 0으로 계산할 것이다. 그렇다면 normal flow는 두 번째 div
의 left, top 값을 어떻게 계산할까? 두 번째 div
역시 left 값은 부모 요소의 left 값과 동일하다. 하지만 top 값의 계산 방식이 조금 달라지는데, 위에 첫 번째 div
가 존재하고 이는 block 요소이므로 top 값은 첫 번째 div
의 height
값을 더한 것이 된다.
다음으로 inline
요소인 span
이 등장하면 normal flow는 배치 방식을 IFC로 변경한다. 줄 바꿈이 되었으므로 left 값은 당연히 0, top 값은 이전 줄까지의 height
값을 모두 더한 것이 되겠다. 그 뒤에 따라오는 요소인 text
, span
, text
역시 전부 inline
요소이므로 normal flow는 IFC 방식으로 left, top 값을 계산할 것이다. 이때 block
요소와 달리 inline
요소의 경우 IFC 방식에 따라 가로로 배치되므로 left 값을 주목해야 한다. 그러므로 첫 번째 span
뒤에 오는 text
의 left 값은 첫 번째 span
의 width
값을 더한 것이 된다. top 값의 경우 줄 바꿈이 없었으므로 이전과 동일하다.
또 하나 IFC 방식에서 주목해야 할 점이 있다. 바로 한 줄에 있는 inline
요소 width
값의 합이 부모 요소의 width
값보다 커지면 줄 바꿈이 일어난다는 점이다. 그러므로 위의 그림에서 다음 줄로 넘어간 text
의 경우에 줄 바꿈이 되었으므로 left 값은 다시 0으로 계산하고, top 값은 이전 줄의 inline
요소 height
값까지 더한 것이 된다.
CSS의 display
값 중에는 아까 살펴본 block
, inline
과 비슷해보이는 inline-block
이라는 값이 있다. 이를 앞서 외부 디스플레이 유형으로 다루지 않은 이유는 공식 문서에서 block
, inline
과 inline-block
을 다른 범주로 분류하고 있기 때문이다.
자세히 살펴보면 block
, inline
은 앞서 살펴본 것처럼 외부 디스플레이 유형으로 분류되어 있지만, inline-block
은 레거시(legacy) 유형으로 분류되어 있다. 그렇다면 여기서의 레거시는 무슨 의미일까?
💡 레거시 유형이란?
: 원래
display
속성은 단일 값만 사용할 수 있지만,block
요소임에도inline
요소처럼 제어할 수 있는 기능이 필요했음
: 이를 추가하기 위해inline-block
처럼 두 개의 값을 붙여서 별도의 기능으로 나타낸 것을 의미함
ex)inline-flex
,inline-grid
위의 정의를 보면 알 수 있듯, 결국 display
의 레거시 유형은 inline
요소가 아닌 것들을 inline
요소처럼 사용하고 싶어서 만들어진 것이라고 보면 된다. 이에 따라 결국 inline-block
은 block
요소이지만 inline
요소처럼 배치하고 싶을 때 사용하는 값이라고 정의할 수 있겠다. 그러므로 normal flow의 계산 방식 역시 block
요소임에도 불구하고 BFC가 아니라 IFC 방식을 따르게 된다.
block
과 inline
요소의 특징을 이해하기 위해 normal flow 개념까지 언급하느라 내용이 좀 길어졌지만, 이번에는 display
속성 중 내부 디스플레이 유형으로 분류되는 값을 한 번 살펴보고자 한다.
내부 디스플레이 유형에 해당하는 값은 보편적으로 flex
, grid
, flow
, flow-root
로 네 가지가 있다. 공식 문서에 따르면 table
, ruby
까지 포함하여 여섯 가지이긴 하지만, 중요도가 낮으므로 이 글에서는 배제했다.
먼저 각각의 값을 살펴보기 전에 내부 디스플레이 유형으로 분류된 값들은 어떤 특징을 가지는지 알 필요가 있다. 외부 디스플레이 유형이 요소가 normal flow에 관여하는 방식을 기준으로 분류한 것이라면, 내부 디스플레이 유형은 요소 내부의 콘텐츠를 배치하는 방식을 기준으로 분류한 것이다.
💡
flex
:
block
요소처럼 동작하면서 내부의 콘텐츠는 자체적인 flexbox model에 따라 배치함
💡
grid
:
block
요소처럼 동작하면서 내부의 콘텐츠는 자체적인 grid model에 따라 배치함
💡
flow
: normal flow에 따라 요소의 콘텐츠를 배치함
: 외부 디스플레이 유형이inline
이라면 inline box 생성하고, 그 외에는 block box를 생성함
💡
flow-root
: 새로운 BFC를 생성하는 block box를 생성하여 콘텐츠를 배치함
간단하게 내부 디스플레이 유형의 특징을 살펴보면 위와 같다. 이를 자세히 살펴보려면 float
, position
등의 속성도 함께 언급해야 하기 때문에 내용이 엄청 길어질 것이다. 또한 서두에서도 언급했듯 이번 글에서는 block
과 inline
에 주목하여 살펴볼 예정이므로 내부 디스플레이 유형은 특징만 간단하게 짚고 넘어가려고 한다. 자세한 내용은 추후에 따로 글을 작성하여 정리할 예정이다.
사실 이전까지 내가 CSS를 사용하는 과정은 다음과 같았다.
(1) 사용하려는 속성 구글링하기
(2) 읽어보고 일단 써보기
(3) 써봤는데 되면 GOOD!
(4) 안 된다면 좀 바꿔서 써보기
위의 과정을 보면 알 수 있겠지만, 일시적으로 눈 앞에 놓인 상황만 해결하는 데 급급했다. 원리를 이해하지 않고 사용부터 하다 보니, 다음에 조금만 상황이 바뀌어서 주어져도 제대로 CSS를 사용할 수가 없었던 것이다.
개인적으로 이 글에서 살펴본 block
요소와 inline
요소의 특징, 레이아웃 배치에 관여하는 normal flow는 CSS를 제대로 사용하기 위한 필수 배경지식이라는 생각이 든다. 이에 대한 이해가 부족하면 CSS의 레이아웃 배치를 제대로 활용할 수 없게 된다.
어떤 기능을 사용하기 전에 원리부터 이해해야 한다는 어쩌면 너무도 당연한 진리를 지금까지 간과하고 있었다는 생각이 든다. 앞으로 어떤 기능을 공부하든지 '잘 되네? 그렇구나!'가 아니라 '왜 이렇게 동작하는 거지?'를 먼저 생각해야겠다고 다시 한 번 다짐하게 되었다.
🙏 출처
https://sorto.me/docs/Web/CSS/display
https://developer.mozilla.org/ko/docs/Web/CSS/display
https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Flow_Layout
https://psy082.github.io/2020/07/20/css-position/