Skip to content
This page has been auto-translated and may contain errors.View in English

디스플레이와 일반 흐름

docs.scrimba.com

CSS를 전혀 적용하지 않은 페이지에 문단 세 개와 링크 몇 개를 넣어도, 요소들은 스스로 자리를 잡습니다. 문단은 페이지 아래로 차례차례 쌓이고, 링크는 여러분이 써넣은 그 위치의 텍스트 안에 자리를 잡습니다. 이렇게 하라고 브라우저에게 시킨 사람은 아무도 없습니다. 레이아웃 규칙을 단 하나도 작성하기 전부터 이미 레이아웃은 존재하며, 이후에 사용하는 모든 기법은 그 상태를 처음부터 만드는 것이 아니라 이미 있는 것을 바꾸는 작업일 뿐입니다. 이번 장에서는 그 출발점과, 그것을 좌우하는 단 하나의 속성을 다룹니다.

일반 흐름

브라우저가 여러분이 작성한 레이아웃 CSS 없이 페이지를 배치할 때는 **일반 흐름(normal flow)**을 사용합니다. 이는 요소들이 스스로 자리를 잡는 기본 방식입니다. 문단이나 제목 같은 블록 요소는 위에서 아래로 쌓이며, 각자 자신만의 줄을 차지합니다. 텍스트와 링크는 한 줄 안에서 왼쪽에서 오른쪽으로 흐르다가, 자리가 부족해지면 다음 줄로 넘어갑니다.

여러분은 이미 흐르는 대상, 즉 박스 모델을 배운 적이 있습니다. 이번 장은 그 위에서 이어지는데, 흐르는 것은 결국 그 박스들이기 때문입니다. 일반 흐름이라는 이름을 붙이는 이유는, 레이아웃의 다른 모든 것이 이것을 기준으로 정의되기 때문입니다. 플렉스박스, 그리드, 포지셔닝은 모두 "기본값과 다르게 배치하라"는 지시일 뿐이므로, 기본값을 알아야 그 변화들이 이해가 됩니다.

**일반 흐름(normal flow)**은 브라우저의 기본 레이아웃으로, flex나 grid, float, 포지셔닝이 개입하기 전에 얻게 되는 배치 방식입니다. 블록 박스는 소스 순서대로 페이지 아래로 세로로 쌓이며, 각각 새 줄에서 시작해 사용 가능한 전체 너비를 차지합니다. 인라인 박스는 왼쪽에서 오른쪽으로 쓰는 언어라면 줄을 따라 왼쪽에서 오른쪽으로 흐르며, 현재 줄이 다 차면 다음 줄로 넘어갑니다.

이 개념에 이름을 붙이는 이유는, 레이아웃 도구들이 이것에서 벗어난 형태로 정의되기 때문입니다. 컨테이너에 display: flex를 설정하면, 그 컨테이너의 자식들을 일반 흐름 대신 flex 규칙으로 배치하라고 브라우저에게 지시하는 것입니다. 기본값은 절대 사라지지 않으며, 개별 컨테이너를 그로부터 벗어나게 할 뿐입니다. 스타일이 전혀 없는 문서도 여전히 읽을 수 있는 이유가 바로 여기에 있습니다. 일반 흐름은 실제로 존재하는 레이아웃이며, 레이아웃이 없는 상태가 아닙니다.

**일반 흐름(normal flow)**은 float, 포지셔닝, flex, grid가 아무것도 바꾸기 전에 브라우저가 기본으로 적용하는 레이아웃 모드입니다. 여기에는 함께 작동하는 두 개의 하위 모드가 있습니다. 블록 레이아웃은 블록 레벨 박스를 소스 순서대로 페이지 아래로 세로로 쌓고, 인라인 레이아웃은 인라인 레벨 박스를 한 줄 안에서 가로로 배치하며 줄 상자(line box)를 넘어가면 줄을 바꿉니다. 일반 흐름으로 배치된 블록 박스는 사용 가능한 전체 너비를 차지하고 새 줄에서 시작하며, 인라인 박스는 자신의 콘텐츠만큼의 너비만 차지하고 현재 줄 안에 자리를 잡습니다.

이 개념을 정확히 명명하는 것이 중요한 이유는, 레이아웃 시스템 전체가 이것에 대한 대안들의 집합으로 구성되어 있기 때문입니다. display: flexdisplay: grid는 컨테이너의 내부 레이아웃을 flex 또는 grid 규칙으로 대체하고, position: absolutefloat는 박스를 일반 흐름에서 완전히 빼내어 주변 콘텐츠가 마치 그 박스가 없는 것처럼 배치되게 합니다. 어느 경우든 일반 흐름은 여러분이 벗어나고 있는 기준선이며, 명시적으로 흐름에서 빠져나오거나 다른 레이아웃 모드로 넘겨지지 않은 박스는 여전히 흐름 안에 있습니다. 스타일시트가 없는 문서도 나름대로 합리적인 순서로 렌더링되는 이유가 바로 여기에 있습니다. 블록과 인라인 흐름은 대체 수단이 아니라 기본값입니다.

Juno일반 흐름 일반 흐름은 아무 노력 없이도 얻는 레이아웃입니다. 블록은 페이지 아래로 쌓이고, 텍스트와 링크는 줄을 따라 흐릅니다. 아무도 이것을 켜지 않아도, CSS를 작성하기 전부터 이미 존재합니다. 레이아웃의 다른 모든 것은 이 기본값을 바꾸는 작업이므로, 먼저 기본값을 그려보는 것이 도움이 됩니다.
Juno일반 흐름 일반 흐름은 브라우저의 기본값입니다. 블록은 소스 순서대로 위에서 아래로 쌓이고, 인라인 박스는 줄을 따라 흐르다가 줄을 바꿉니다. flex, grid, 포지셔닝은 모두 컨테이너를 이 흐름에서 벗어나게 하는 방법일 뿐, 어디서나 이를 완전히 대체하지는 않습니다. 스타일이 없는 페이지도 잘 읽히는 이유는 일반 흐름이 실제 레이아웃이지, 레이아웃의 부재가 아니기 때문입니다.
Juno일반 흐름 일반 흐름은 세로로 쌓는 블록 레이아웃과 줄을 따라 흐르는 인라인 레이아웃이 합쳐진 것으로, 다른 무언가가 박스를 건드리기 전에 기본으로 적용됩니다. display: flexdisplay: grid는 컨테이너의 내부 레이아웃을 바꾸고, floatposition: absolute는 박스를 흐름에서 빼내어 형제 요소가 그것을 무시하게 만듭니다. 별도로 빼내지 않은 것은 모두 흐름 안에 남아 있으며, 이것이 스타일시트 없는 문서도 순서대로 렌더링되는 이유입니다.

블록 박스와 인라인 박스

일반 흐름에서 요소는 크게 두 가지 종류로 나뉩니다. **블록 박스**는 컨테이너의 전체 너비를 차지하며 자신만의 줄에서 쌓이고, 다음 요소를 그 아래로 밀어냅니다. 문단 <p>, 제목 <h1>, <div>는 모두 블록이며, 그래서 이들이 한 줄씩 아래로 늘어서는 것입니다.

인라인 박스는 다릅니다. 텍스트 줄 안에 자리를 잡고 콘텐츠에 필요한 만큼의 공간만 차지하므로, 여러 개가 한 줄을 나눠 쓸 수 있습니다. <span>이나 링크 <a>는 인라인이며, 그래서 문장 안의 링크가 자신만의 줄로 튀지 않고 문장의 흐름 속에 머무는 것입니다.

html
<p>이 문단은 블록이므로 자신만의 줄을 차지합니다.</p>
<p>더 알아보려면 <a href="/ko/css/box-model">박스 모델</a>을 읽어 보세요.</p>
<!-- 링크는 인라인이므로 문장 안에 그대로 머뭅니다 -->

일반 흐름에 있는 모든 박스는 블록 레벨이나 인라인 레벨 중 하나로 배치되며, 이 둘은 서로 다른 규칙을 따릅니다. **블록 박스**는 새 줄에서 시작하고, 기본적으로 사용 가능한 너비를 채우며, 세로로 쌓입니다. <div>, <p>, <h1>, <section>은 기본적으로 블록입니다. 인라인 박스는 텍스트와 함께 줄 안에서 흐르며, 콘텐츠 너비만 차지하고, 줄이 바뀌기 전까지 이웃 요소 옆에 자리를 잡습니다. <span>, <a>, <strong>은 기본적으로 인라인입니다.

사람들이 자주 걸려드는 차이는 인라인 박스가 무시하는 속성들입니다. 인라인 박스는 width, height, 위아래 마진을 무시합니다. <span>width: 200px를 설정해도 아무 일도 일어나지 않는 이유는, 인라인 박스의 크기는 여러분이 아니라 그 콘텐츠가 결정하기 때문입니다. 좌우 패딩과 마진은 적용되지만, 위아래 여백은 블록에서처럼 주변 줄을 밀어내지 않습니다.

css
.tag {
  width: 200px;        /* 무시됨: span은 인라인이라 콘텐츠에 따라 크기가 정해짐 */
  padding: 0 8px;      /* 가로 패딩은 적용됨 */
  margin-top: 40px;    /* 무시됨: 인라인 박스에는 위아래 마진이 없음 */
}

일반 흐름에서 박스는 디스플레이 타입에 따라 블록 레이아웃 또는 인라인 레이아웃으로 배치되며, 이 둘의 차이는 "쌓이는지 줄바꿈되는지"를 넘어섭니다. **블록 박스**는 자신의 앞뒤로 줄바꿈을 만들고, 너비가 지정되지 않으면 포함 블록의 인라인 방향 크기를 전부 차지하며, 네 방향 마진과 두 치수 모두를 존중합니다. 인라인 박스는 줄 상자(line box)의 일부가 되고, 콘텐츠에 따라 크기가 정해지며, 그 배치는 widthheight가 아니라 line-height와 baseline 정렬에 의해 좌우됩니다.

정확히 짚어야 할 부분은 인라인 박스가 어떤 속성을 무시하는가입니다. <span>이나 <a> 같은 비교체(non-replaced) 인라인 박스에는 widthheight가 적용되지 않는데, 그 크기가 콘텐츠와 주변 줄에서 결정되기 때문입니다. 위아래 마진은 계산은 되지만 줄 높이에 영향을 주지 않으므로 인접한 줄을 절대 밀어내지 않고, 위아래 패딩은 시각적으로는 그려지지만 줄 상자의 높이를 바꾸지 않으므로 이웃한 줄과 겹칠 수 있습니다. 좌우 마진과 패딩은 적용되며 인라인 이웃 요소를 실제로 밀어냅니다. <img> 같은 교체(replaced) 인라인 요소는 예외로, 고유한(intrinsic) 크기를 가지고 있어서 인라인 레벨임에도 widthheight가 적용됩니다.

css
.badge {              /* .badge는 <span>이며 기본적으로 인라인입니다 */
  width: 120px;       /* 효과 없음: width는 인라인 박스에 적용되지 않음 */
  height: 40px;       /* 같은 이유로 효과 없음 */
  padding: 12px;      /* 좌우는 이웃을 밀어내지만, 위아래는 줄과 겹칠 수 있음 */
  margin: 8px 0;      /* 세로 8px은 무시되고, 가로 0은 적용됨 */
}
Juno블록 박스와 인라인 박스<p>, <div> 같은 블록 박스는 전체 너비를 차지하며 자신만의 줄에 쌓입니다. <span>, <a> 같은 인라인 박스는 줄 안에 자리를 잡고 필요한 만큼의 공간만 차지합니다. 그래서 링크가 자신만의 행으로 줄바꿈되지 않고 문장 안에 그대로 머무는 것입니다.
Juno블록 박스와 인라인 박스 블록 박스는 너비를 채우며 쌓이고, 인라인 박스는 줄을 따라 흐르며 콘텐츠 크기에 맞춰집니다. 함정은 인라인 박스가 width, height, 세로 마진을 무시한다는 점입니다. 그래서 <span>width를 설정해도 아무 효과가 없습니다. 가로 패딩과 마진은 여전히 작동하는데, 바로 이 점 때문에 사람들이 헷갈리게 됩니다.
Juno블록 박스와 인라인 박스 인라인 박스는 콘텐츠와 줄 상자에 의해 크기가 정해지므로 widthheight가 적용되지 않고, 세로 마진과 패딩은 인접한 줄을 밀어내지 않습니다. 가로 마진과 패딩은 적용되며 이웃 요소를 밀어냅니다. 예외는 <img> 같은 교체 요소로, 자체적인 크기를 가지고 있어 인라인이더라도 widthheight를 받아들입니다.

display 속성

모든 요소에는 기본 종류, 즉 블록 또는 인라인이 있지만, 여기에 묶여 있어야 하는 것은 아닙니다. display 속성을 사용하면 요소가 어느 쪽처럼 동작할지 바꿀 수 있습니다. 링크에 display: block을 설정하면 이제 자신만의 줄을 차지하고, 리스트 항목에 display: inline을 설정하면 한 줄 안에 자리를 잡습니다.

흔한 문제를 해결해주는 세 번째 값이 있습니다: display: inline-block입니다. 인라인 박스처럼 줄 안에서 흐르지만, 블록처럼 너비, 높이, 세로 패딩을 받아들입니다. 버튼이나 이웃 요소와 나란히 있으면서도 정해진 크기를 가져야 하는 내비게이션 필(pill) 같은 것에 딱 맞습니다.

css
.nav-link {
  display: inline-block;   /* 줄 안에서 흐르지만 width와 padding을 받아들임 */
  padding: 8px 16px;       /* 순수 인라인과 달리 세로 패딩도 이제 작동함 */
}

display 속성은 박스가 어떻게 배치될지를 정하며, 흐름과 관련된 세 값은 block, inline, inline-block입니다. display: block은 요소의 기본값이 무엇이든 상관없이 박스가 자신만의 줄에서 시작하고 너비를 채우게 만듭니다. display: inline은 박스가 줄 안에서 흐르게 하고 width, height, 세로 마진을 버리게 만듭니다. 둘 다 요소의 의미는 바꾸지 않고, 배치만 바꿉니다.

inline-block은 유용한 혼합형입니다. 박스는 인라인 박스처럼 줄 안에서 흘러서 여러 개가 나란히 자리를 잡지만, 블록처럼 width, height, 세로 패딩과 마진을 받아들입니다. 여러 버튼이나 내비게이션 링크처럼, 한 줄에 늘어서 있으면서도 실제 치수가 필요한 것들에는 플렉스박스로 넘어가지 않고 이것을 쓰면 됩니다. 정렬과 여백이 필요한 요소들의 전체 줄이나 그리드를 배치해야 한다면 플렉스박스display: flex가 더 나은 도구이고, inline-block은 한 줄에 크기가 있는 몇 개의 박스를 놓는 작은 규모의 상황을 위한 것입니다.

css
.stat {
  display: inline-block;   /* 형제 요소와 나란히 한 줄에 자리 잡음 */
  width: 120px;            /* 하지만 고정 너비를 가짐, inline이었다면 무시되었을 것 */
  padding: 12px;           /* 위아래를 포함해 전체 패딩이 적용됨 */
}

display는 박스의 레이아웃 모드를 선택하며, 일반 흐름 안에 남겨두는 세 값은 block, inline, inline-block입니다. block은 앞뒤로 줄바꿈을 만들고 포함 블록의 인라인 방향 크기를 채우는 박스를 만들고, inline은 줄 상자에 합류하고 width, height, 세로 마진을 버리는 박스를 만듭니다. display를 설정하는 것은 의미(semantics)에는 절대 영향을 주지 않고 배치에만 영향을 줍니다. display: inline으로 설정된 <div>는 DOM과 보조 기술(assistive tech)에게는 여전히 <div>이며, 배치만 인라인처럼 되는 것입니다.

inline-block은 의도적으로 만들어진 혼합형입니다. 박스 자체는 인라인 레벨이라 줄 상자에 참여하며 인라인 이웃 요소들과 나란히 자리를 잡지만, 그 내부는 블록으로 배치되어 width, height, 네 방향의 마진과 패딩이 모두 적용되어 실제 레이아웃 공간을 차지합니다. 그래서 플렉스 컨테이너를 쓰고 싶지 않은, 한 줄에 크기가 있는 소수의 박스들을 놓는 상황에 알맞습니다. 예를 들면 고정 너비의 통계 블록이나 내비게이션 필(pill) 같은 것입니다. 주의할 점은 인라인 레벨이기 때문에, HTML에서 두 inline-block 요소 사이의 공백이 실제 간격으로 렌더링된다는 것인데, 이는 아래 심화 섹션에서 다룹니다. 한 줄 전체에 정렬, 분배, 줄바꿈이 필요한 경우에는 플렉스박스의 flex 레이아웃을 쓰는 것이 낫습니다. inline-block은 좁은 용도의 도구이지, 범용 도구가 아닙니다.

css
.pill {
  display: inline-block;   /* 인라인 레벨 박스, 블록 레벨 내부 */
  width: 96px;             /* 적용됨, 내부가 블록으로 배치되기 때문 */
  padding: 10px 14px;      /* 네 방향 모두 레이아웃 공간을 차지함 */
  margin: 0 4px;           /* 이제 세로 마진도 적용됨 */
}
Junodisplay 속성display 속성은 요소가 블록처럼 동작할지 인라인 박스처럼 동작할지를 바꿉니다. block은 자신만의 줄을 차지하고, inline은 텍스트 줄 안에 자리를 잡습니다. 유용한 중간 옵션은 inline-block으로, 줄 안에서 흐르면서도 너비와 패딩을 받아들여서 버튼이나 내비게이션 링크에 딱 맞습니다.
Junodisplay 속성display는 의미가 아니라 배치를 설정합니다: block, inline, 또는 혼합형인 inline-block입니다. 크기가 있는 몇 개의 박스를 한 줄에 나란히 놓고 싶을 때는 inline-block을 쓰세요. 인라인처럼 흐르면서도 width, height, 전체 패딩을 받아들이기 때문입니다. 정렬과 여백이 필요한 전체 줄에는 대신 플렉스박스를 쓰세요.
Junodisplay 속성display는 레이아웃 모드만 정하고 의미는 절대 바꾸지 않으므로, 인라인 <div>도 DOM에게는 여전히 <div>입니다. inline-block은 내부는 블록 레벨인 인라인 레벨 박스이므로, 한 줄에 자리를 잡으면서도 width, height, 네 방향 마진을 존중합니다. 크기가 있는 몇 개의 박스에만 이것을 쓰고, 진짜 한 줄에는 플렉스박스를 쓰세요. 그리고 인접한 박스 사이에 남는 공백 간격도 신경 쓰세요.

요소 숨기기: display none과 visibility hidden

때로는 요소가 보이지 않게 만들어야 합니다. 방법은 두 가지가 있고, 서로 다르게 동작합니다. display: none은 요소를 완전히 제거합니다. 요소가 사라지고 빈틈도 남지 않아서, 마치 페이지에 전혀 없었던 것처럼 됩니다. visibility: hidden은 요소를 보이지 않게 만들지만 자리는 그대로 남겨서, 원래 있던 자리에 빈 구멍이 생깁니다.

어느 것을 쓸지는 그 공간을 되돌려받고 싶은지에 따라 달라집니다. 닫힌 메뉴처럼 무언가를 완전히 없애고 싶다면 display: none을 쓰세요. 레이아웃이 갑자기 움직이지 않게 하면서 무언가를 숨기고 싶다면 visibility: hidden을 쓰세요. 그 박스의 자리가 그대로 예약되어 있기 때문입니다.

css
.closed-menu {
  display: none;          /* 사라지고, 빈틈도 남지 않음 */
}
.placeholder {
  visibility: hidden;     /* 보이지 않지만, 여전히 자리를 차지함 */
}

요소를 숨기는 두 방법은 서로 바꿔 쓸 수 있는 것이 아닙니다. display: none은 요소를 일반 흐름에서 완전히 빼냅니다. 박스를 전혀 생성하지 않고, 공간도 차지하지 않으며, 주변 요소들은 그 요소가 원래 없었던 것처럼 자리를 좁힙니다. visibility: hidden은 박스를 흐름 안에 유지하고 그 공간을 예약하므로 레이아웃이 이동하지 않으며, 요소는 그냥 보이지 않게 그려질 뿐입니다.

시각적인 차이만큼 중요한 접근성 차이도 있습니다. display: none이 적용된 요소는 접근성 트리에서도 제거되므로 스크린 리더가 건너뜁니다. 이는 접힌 패널처럼 아예 존재하지 않는 콘텐츠에는 올바른 동작입니다. visibility: hidden 역시 공간은 유지하면서 콘텐츠를 스크린 리더로부터 숨깁니다. 시각적으로는 사라지되 보조 기술에는 여전히 안내되어야 하는 것이 필요하다면, 이 둘 중 어느 것도 정답이 아닙니다. 그럴 때 필요한 것이 visually-hidden 유틸리티 클래스이며, 이는 CSS의 동작 원리에서 그 의미와 함께 읽어볼 수 있습니다.

css
.tab-panel[hidden] {
  display: none;          /* 흐름과 접근성 트리 모두에서 제거됨 */
}
.spacer {
  visibility: hidden;     /* 자리는 유지되지만, 스크린 리더에서는 여전히 숨겨짐 */
}

display: nonevisibility: hidden은 둘 다 요소를 숨기지만, 흐름, 박스 트리, 접근성 측면에서 다르게 동작합니다. display: none은 박스를 전혀 생성하지 않습니다. 요소는 레이아웃에서 사라지고, 공간을 전혀 차지하지 않으며, 자손들도 자신의 display 값과 무관하게 함께 사라집니다. visibility: hidden은 박스를 정상적으로 생성하므로 흐름 안에서 전체 공간을 차지하고 그림만 생략합니다. 심지어 자손이 visibility: visible을 설정해서, 그 외에는 숨겨진 조상 안에서 다시 나타날 수도 있는데, display: none에서는 이것이 절대 불가능합니다.

이런 접근성과 동작상의 결과가 바로 신중하게 선택해야 하는 이유입니다. display: nonevisibility: hidden 둘 다 요소를 접근성 트리에서 제거하므로, 스크린 리더는 어느 쪽도 안내하지 않습니다. 그래서 시각적으로는 사라지되 여전히 소리로 읽혀야 하는 콘텐츠에는 둘 다 맞지 않습니다. 대표적인 예가 "본문으로 건너뛰기" 링크나 스크린 리더 전용 레이블입니다. 이런 것들은 박스를 픽셀 단위로 잘라내면서도 접근성 트리에는 남겨두는 visually-hidden 패턴이 필요하며, 여기서 다룬 두 속성 중 어느 것도 해당되지 않습니다. 실무적으로 두 가지를 더 짚어보면, display: noneopacityvisibility처럼 상태 사이를 전환하거나 애니메이션으로 처리할 수 없고, display: none으로 설정된 요소는 포커스를 받을 수 없으며 그 안의 폼 컨트롤은 제출되지 않습니다. 반면 visibility: hidden이 적용된 컨트롤도 마찬가지로 건너뛰어지지만 그 자리는 유지됩니다. 완전히 제거하려면 display: none을, 레이아웃을 그대로 유지하면서 숨기려면 visibility: hidden을, 보조 기술이 여전히 접근해야 한다면 클리핑 유틸리티를 선택하세요.

css
.dropdown[aria-expanded="false"] .menu {
  display: none;          /* 완전히 제거됨: 박스도 공간도 없고, 포커스도 받지 않음 */
}
.avatar-slot {
  visibility: hidden;     /* 박스와 공간은 유지되고, 그림만 생략됨 */
}
Juno요소 숨기기: display none과 visibility hidden 숨기는 두 가지 방법: display: none은 요소를 제거하고 빈틈도 남기지 않으며, visibility: hidden은 보이지 않게 만들지만 자리는 그대로 유지합니다. 닫힌 메뉴처럼 공간까지 없애고 싶다면 display: none을 선택하세요. 레이아웃이 갑자기 움직이지 않게 하고 싶다면 visibility: hidden을 선택하세요.
Juno요소 숨기기: display none과 visibility hiddendisplay: none은 요소를 흐름에서 빼내어 아무것도 그 자리를 예약하지 않게 만들고, visibility: hidden은 박스와 그 공간을 유지하면서 그림만 숨깁니다. 둘 다 요소를 스크린 리더로부터도 숨기므로, 시각적으로는 사라지되 여전히 안내되어야 하는 것에는 둘 다 맞지 않습니다. 그 역할은 visually-hidden 유틸리티 클래스가 담당합니다.
Juno요소 숨기기: display none과 visibility hiddendisplay: none은 박스를 전혀 생성하지 않고 공간도 차지하지 않습니다. visibility: hidden은 박스와 공간을 유지하면서 그림만 생략하며, 자식이 visibility: visible을 설정해 다시 나타날 수도 있습니다. 둘 다 접근성 트리에서 빠지므로, 건너뛰기 링크나 스크린 리더 레이블에는 클리핑 유틸리티가 필요하지, 둘 중 어느 것도 맞지 않습니다. display: none은 애니메이션이 불가능하고 그 안의 컨트롤은 포커스도 받지 않고 제출도 되지 않는다는 점을 기억하세요.

display가 내부 레이아웃을 바꾸는 방식

여러분은 이미 display가 요소를 블록과 인라인 사이에서 바꾸는 것을 보았습니다. 하지만 더 깊이 들어가면 그 이상의 역할을 합니다. 같은 속성이 컨테이너를 플렉스박스나 그리드로 바꾸는 역할도 하는데, 이 둘은 자식들을 행과 열로 배치하는 현대적인 도구입니다. 지금은 display가 박스가 어떻게 배치되는지, 그리고 그 안의 자식들이 어떻게 배치되는지를 결정하는 단 하나의 다이얼이라는 점만 기억하면 됩니다.

레이아웃은 한 번에 켜는 커다란 스위치가 아닙니다. 다른 배치가 필요한 특정 컨테이너에만 display를 바꾸고, 그대로 두는 나머지는 일반 흐름에 머뭅니다. 플렉스박스포지셔닝 장은 여기서부터 이야기를 이어갑니다.

display는 사실 두 가지를 동시에 제어합니다. 박스 자신이 형제들 사이에서 어떻게 자리를 잡는지, 그리고 박스가 자신의 자식들을 어떻게 배치하는지입니다. display: blockdisplay: inline은 주로 첫 번째에 관한 것입니다. display: flexdisplay: grid는 두 번째를 바꿉니다. 컨테이너 자신은 여전히 블록으로서 일반 흐름에 참여하지만, 그 안에서 자식들은 블록-인라인 흐름 대신 flex나 grid 규칙으로 배치됩니다.

이것이 바로 플렉스박스로 넘어가더라도 흐름에 대해 배운 것을 모두 버리게 되지 않는 이유입니다. 플렉스 컨테이너는 부모의 일반 흐름 안에서 여전히 블록 박스이며, 오직 그 자식들만 배치 모드를 바꿉니다. 일반 흐름은 여전히 주변의 기본값으로 남아 있고, 필요한 특정 컨테이너에만 flex나 grid를 선택적으로 적용하는 것입니다. 포지셔닝 장에서는 자식들의 배치 방식을 바꾸는 것이 아니라 박스를 흐름에서 완전히 빼내는 또 다른 방법을 다룹니다.

display 값은 실제로 두 가지 타입을 동시에 나타냅니다. 박스가 부모의 레이아웃에 어떻게 참여하는지를 말하는 외부(outer) 타입과, 박스가 자신의 자식들을 어떻게 배치하는지를 말하는 내부(inner) 타입입니다. display: block은 외부는 block, 내부는 flow입니다. display: flex는 외부는 block, 내부는 flex입니다. display: inline-flex는 외부는 inline, 내부는 flex입니다. 이 두 부분으로 나뉜 모델 때문에, 플렉스 컨테이너는 그 자식들이 flex 규칙을 따르는 동안에도 자신은 여전히 블록으로서 일반 흐름 안에 자리를 잡습니다. 여러분이 바꾼 것은 내부 타입이지, 외부 타입이 아닌 것입니다.

여기서 짚어야 할 값이 하나 더 있습니다: display: flow-root입니다. 이것은 박스에 정상적인 내부 흐름을 주면서도 새로운 블록 포맷팅 컨텍스트(BFC: 내부가 외부와 상호작용하지 않는 독립된 레이아웃 영역으로, 그 안의 float는 그 안에만 갇히고 그 안의 마진은 경계를 넘어 병합되지 않습니다)를 강제로 만듭니다. flow-root가 등장하기 전에는 사람들이 float된 자식을 가두기 위해 overflow: hidden이나 clearfix 트릭으로 BFC를 유발했습니다. flow-root는 부작용 없이 "이것을 가둬라"라고 명시적으로 말하는 방법입니다. 또한 박스 모델에서 설명한 부모-자식 마진 병합도 막아줍니다. 플렉스박스에서 컨테이너를 display: flexdisplay: grid로 바꿀 때도 마찬가지로 새로운 포맷팅 컨텍스트를 만드는 것인데, 이것이 바로 float 시대의 레이아웃보다 현대적인 레이아웃 안에서 마진이 더 예측 가능하게 동작하는 이유 중 하나입니다.

css
.media {
  display: flow-root;     /* float된 자식을 가둠, clearfix 트릭 필요 없음 */
}
.gallery {
  display: flex;          /* 일반 흐름 안의 외부 block, 자식을 위한 내부 flex */
}
Junodisplay가 내부 레이아웃을 바꾸는 방식 블록과 인라인을 바꾸는 그 같은 display 속성이, 컨테이너를 자식 배치를 위한 플렉스박스나 그리드로 바꾸는 역할도 합니다. 레이아웃은 한 번에 켜는 스위치가 아닙니다. 필요한 컨테이너에만 display를 바꾸고 나머지는 일반 흐름에 그대로 둡니다. 플렉스박스와 포지셔닝 장이 여기서부터 이야기를 이어갑니다.
Junodisplay가 내부 레이아웃을 바꾸는 방식display는 박스가 형제들 사이에서 어떻게 자리 잡는지와, 자신의 자식들을 어떻게 배치하는지를 모두 관리합니다. display: flexdisplay: grid는 두 번째를 바꾸므로, 플렉스 컨테이너는 자식이 flex 규칙으로 바뀌는 동안에도 일반 흐름 속의 블록으로 남습니다. 그래서 플렉스박스를 배우는 것은 흐름을 대체하는 것이 아니라 흐름 위에 쌓아 올리는 것입니다.
Junodisplay가 내부 레이아웃을 바꾸는 방식display 값은 박스가 부모에 어떻게 합류하는지를 나타내는 외부 타입과, 자식을 어떻게 배치하는지를 나타내는 내부 타입을 함께 담고 있습니다. 그래서 플렉스 컨테이너는 자식이 flex로 바뀌는 동안에도 흐름 속의 블록으로 남습니다. display: flow-root는 정상적인 내부 흐름을 유지하면서 새로운 블록 포맷팅 컨텍스트를 시작하므로, 예전의 overflow나 clearfix 트릭 없이도 float를 가두고 마진 병합을 막습니다. flex와 grid 컨테이너도 자신만의 컨텍스트를 만들며, 이것이 바로 그 안에서 마진이 더 예측 가능하게 동작하는 이유입니다.