C.W.K.
Stream
Lesson 02 of 04 · published

display 와 normal flow: element 가 스스로 배치되는 방법

~11 min · display, block, inline, flow, formatting-context

Level 0Markup Novice
0 XP0/34 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Normal flow 는 너가 아무것도 안 시킬 때 브라우저가 하는 것. 대부분의 layout 이 그걸 nudge 하는 거."

Normal Flow: 기본 행동

Positioning, flex, grid 없이 element 더미를 페이지에 넣으면, 브라우저가 normal flow 로 배치:

  • Block-level element 가 수직 stack, 각자 자기 줄에서 컨테이너 풀 너비.
  • Inline-level element 가 옆에 앉아 왼쪽-오른쪽 (RTL 언어는 오른쪽-왼쪽) 으로 흐르는 줄, 컨테이너 가장자리 닿으면 wrap.
  • 수직 방향이 block 축; 수평 방향이 inline 축. (수직 쓰기 모드 — 일본어, 몽골어 — 에서 뒤집힘. 그래서 방향이 아니라 축으로 명명.)

모든 display 값이 이 기본을 tweak 하는 레시피.

핵심 display

  • block — block-level: 새 줄, 컨테이너 풀 너비. <div>, <p>, <h1><h6>, <section>, <article>, <ul>, <li> 등의 기본.
  • inline — 텍스트 흐름에 앉음, 새 줄 없음, width/height/수직 margin 무시. <span>, <a>, <em>, <strong>, <code> 의 기본.
  • inline-block — 텍스트 흐름에 앉지만 (inline) width/height/모든 margin 받음 (block 같은 내부). 인라인 버튼, 배지, custom 컨트롤의 hybrid.
  • none — layout 에서 완전 제거. 안 보임, flow 에 없음, focusable 안 됨. visibility: hidden 과 달라 — 그건 element 숨기지만 공간 유지.
  • flex — element 를 flex 컨테이너로 만듦; 자식들이 정렬 컨트롤과 함께 한 방향으로 배치. (Track 5.)
  • grid — element 를 grid 컨테이너로 만듦; 자식들이 행과 열에 배치. (Track 6.)
  • contents — element 자체가 박스 트리에서 사라지지만 자식은 남음. Layout 영향 없이 semantic 컨테이너 unwrap 에 유용.
  • list-item — marker 가진 block-level (<li> 의 기본). 어떤 element 든 리스트 항목으로 만들 수 있어.
  • flow-root — 새 block formatting context (BFC) 를 만드는 block-level. Clearfix hack 없이 안의 float 클리어, 자식과 margin collapse 방지, float 포함 용.

Block Formatting Context (BFC)

BFC 는 margin 이 탈출 못 하고, float 가 포함되고, 특정 layout 규칙이 제한되는 격리된 layout 영역. 새 BFC 가 만들어지는 방법:

  • display: flow-root (모던하고 깨끗한 방법)
  • Float 자체
  • display: inline-block
  • display: flex 또는 grid
  • overflow: hidden, auto, 또는 scroll (visible 외)
  • position: absolute 또는 fixed
  • contain: layout 또는 paint 또는 strict

부모에서 float 가 새지 않게 overflow: hidden 더하는 자신을 발견하면, 모던 fix 는 display: flow-root — 부작용 없이 BFC 만들어.

display: none vs visibility: hidden vs opacity: 0 vs hidden 속성

  • display: none — layout 에서 사라짐. 안 보임, focusable 안 됨, 공간 안 차지, 기본 ARIA-hidden.
  • visibility: hidden — 안 보이지만 공간 여전히 차지. Focusable 안 됨.
  • opacity: 0 — 보임 (트리 안, flow 안, focusable, clickable) 하지만 투명. 애니메이션에만, 숨김 용 절대 X.
  • HTML hidden 속성 — display: none 과 동일, 하지만 CSS 안 건드리고 HTML/JS 에서 설정 가능.
  • aria-hidden="true" — screen reader 에서 숨지만 보임. Element 가 시각적으로도 숨겨져야 하면 위 중 하나와 페어.
의도에 맞는 hide 골라. 모두에게 숨기기? display: none. 시각적으로 숨기지만 screen reader 접근 유지 (skip link)? clip-path 가진 custom "visually-hidden" 클래스. 나가는 애니메이션? display: none 쓰지 마 — opacity 애니메이트하고 transitionend 에 display: none 설정.

Visually Hidden — 접근성 표준

가끔 screen reader 에는 보이지만 시각적으로 렌더 안 되는 콘텐츠 원함 (skip link, 숨겨진 label, 디자인이 아이콘으로 교체한 버튼 이름). 커뮤니티 표준 패턴:

Inline 공백 갭

<span>A</span> <span>B</span> 있으면, 그 사이 공백이 보이는 공간으로 렌더 — 인라인 element 가 공백을 단일 공간으로 collapse 해서. 인라인-block 버튼이 가끔 사이에 신비한 갭 있는 이유. Fix: 공백 없이 같은 줄에 놓기, 부모에 font-size: 0 (자식에 reset), 또는 공백이 안 중요한 flexbox 로 전환.

피파의 노트

피파의 WebUI 가 모든 layout 컨테이너에 display: flexdisplay: grid 써. 코드베이스에 float 나 clearfix hack 하나도 없음. 클래식 display: contents 트릭이 한 번 나옴 — 채팅 메시지 리스트에서, <article> 이 시각적으로 분리된 두 그룹 감싸지만 flex layout 의 spacing 을 interrupt 하면 안 됨. 모던 display 모드가 모던 문제 해결.

Code

Block, inline, inline-block 실제·html
<!-- 데모: normal flow -->
<style>
  .block { background: #cdf; padding: 10px; margin: 5px 0; }
  .inline { background: #fdc; padding: 5px; }
  .ib { display: inline-block; background: #cfd; padding: 5px; width: 80px; }
</style>

<div class="block">Block 1 — 풀 너비, 새 줄</div>
<div class="block">Block 2 — 풀 너비, 새 줄</div>

<span class="inline">inline A</span>
<span class="inline">inline B</span>
<span class="inline">inline C</span>

<span class="ib">IB 1</span>
<span class="ib">IB 2</span>
<span class="ib">IB 3</span>
<!-- IB 가 각자 width: 80px 존중; 사이 갭은 source 의 공백 —
     inline gap 섹션 봐 -->
visually-hidden CSS 패턴·css
/* visually-hidden 패턴 — screen reader 전용 콘텐츠 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* 이렇게 써: */
/* <a href="#main" class="visually-hidden focus-visible-show">
     Skip to main content
   </a> */

/* 아이콘 전용 버튼용: */
/* <button>
     <svg aria-hidden="true">...</svg>
     <span class="visually-hidden">Close menu</span>
   </button> */
flow-root, contents — 모던 display 도구·css
/* 모던 BFC: flow-root */

/* 옛 clearfix hack — 더 이상 쓰지 마 */
.cf::after {
  content: '';
  display: table;
  clear: both;
}

/* 모던 등가물 — 선언 하나, pseudo-element 없음 */
.contains-floats {
  display: flow-root;
}

/* overflow: hidden 은 실제로 overflow 숨기길 원할 때만 써 */
.scroll-region {
  overflow: auto;       /* content 가 초과하면 스크롤 */
  max-height: 300px;
}

/* display: contents — element 가 박스 트리에서 사라짐 */
.unwrap {
  display: contents;    /* 자식들이 부모의 sibling 의 sibling 이 됨 */
}
/* 유용: <article> 감싸는 거 semantic 으로 flexbox 한테 안 보이게 만들어
   자식들이 부모의 flex layout 에 직접 참여 */

External links

Exercise

다섯 항목 가진 네비게이션 만들기. 세 가지 방식으로 렌더: (1) 기본 block element 로 (각자 자기 줄), (2) inline-block 으로 (한 줄에 앉아, 공백 갭 보이게 — DevTools 로 측정), (3) flexbox row 로 (gap 으로 제어, 공백 이슈 없음). 그러고 나서 visually-hidden 패턴 써서 skip link 추가하고 focus 받을 때만 나타나는지 확인.
Hint
DevTools → Layout 패널이 박스 보여 줘. visually-hidden skip link 에 position: absolute; clip-path: inset(50%); width: 1px; height: 1px; 줘 — 보이게 만드는 :focus 규칙과 함께. URL 바에서 페이지로 Tab 하면 skip link 가 나타나야 해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.