Flexbox

김동현·2026년 3월 18일

mdn 학습 번역 - CSS

목록 보기
26/190

안녕하세요! 프론트엔드 개발자를 향해 힘차게 나아가고 계신 여러분, 진심으로 환영합니다. 저는 여러분의 CSS 레이아웃 정복을 도와드릴 강사입니다.

오늘은 드디어 CSS 레이아웃의 꽃이자 현대 웹 개발의 구원자, 플렉스박스(Flexbox)를 배울 차례입니다! 과거에는 요소들을 가로로 배치하거나 수직 중앙 정렬을 하기 위해 float이나 position 속성을 쓰며 온갖 편법(Hack)을 동원하느라 정말 고생이 많았는데요. Flexbox의 등장으로 이 모든 고통이 사라졌습니다. 실무에서 하루에도 수십 번씩 쓰게 될 이 마법 같은 도구를, 공식 문서의 모든 내용에 제 생생한 실무 꿀팁을 얹어서 아주 쉽고 친절하게 설명해 드릴게요. 자, 가볼까요?


플렉스박스 (Flexbox)

플렉스박스(Flexbox)는 행(row)이나 열(column) 방향으로 아이템들을 배치하기 위한 1차원(one-dimensional) 레이아웃 방식입니다. 아이템들은 여분의 공간을 채우기 위해 유연하게(flex) 늘어나거나, 좁은 공간에 맞추기 위해 줄어듭니다. 이 문서에서는 플렉스박스의 모든 기본 원리를 설명합니다.

선행 조건 (Prerequisites):HTML로 콘텐츠 구조화하기, CSS 스타일링 기초, 기본적인 텍스트와 폰트 스타일링 지식, 그리고 CSS 레이아웃 기초 개념에 대한 친숙함.
학습 목표 (Learning outcomes):
  • 플렉스박스의 목적 — 블록(block)이나 인라인(inline) 요소들의 집합을 1차원 방향으로 유연하게 배치하기.
  • 플렉스 관련 용어 — 플렉스 컨테이너(flex container), 플렉스 아이템(flex item), 메인 축(main axis), 교차 축(cross axis).
  • display: flex가 기본적으로 제공하는 동작 이해하기.
  • 새로운 행이나 열로 콘텐츠를 줄 바꿈(wrap)하는 방법.
  • 플렉스 아이템의 유연한 크기 조절 및 순서 변경.
  • 콘텐츠의 여백 분배(justifying) 및 정렬(aligning).

왜 플렉스박스를 사용할까요? (Why flexbox?)

CSS 플렉시블 박스 레이아웃(Flexible box layout)은 다음과 같은 일들을 가능하게 해 줍니다:

  • 부모 요소 안에서 콘텐츠 블록을 수직으로 중앙 정렬하기.
  • 사용 가능한 너비/높이가 얼마나 되든 상관없이, 컨테이너 안의 모든 자식 요소들이 동일한 크기의 너비/높이를 나누어 가지게 만들기.
  • 다단(multiple-column) 레이아웃에서 각 열의 콘텐츠 양이 다르더라도, 모든 열이 동일한 높이를 가지도록 만들기.

플렉스박스 기능들은 여러분이 1차원 레이아웃을 구성할 때 만나는 문제들을 완벽하게 해결해 주는 마스터키가 될 수 있습니다. 자, 본격적으로 파헤쳐 볼까요?

💡 강사님의 실무 팁!
"수직 중앙 정렬"이라는 말에 옛날 개발자들은 눈물을 흘렸습니다. 예전엔 이걸 하려고 눈금자 대고 여백을 계산하거나 표(table) 태그를 억지로 썼거든요. 이제는 align-items: center 하나면 모든 게 끝납니다! 이것만으로도 Flexbox를 배울 가치는 충분하죠.


간단한 예제 소개 (Introducing a simple example)

이 문서에서는 플렉스박스가 어떻게 작동하는지 이해하기 위해 일련의 실습을 진행할 것입니다. 시작하려면 로컬 환경에 HTML과 CSS를 복사해 두는 것이 좋습니다. 모던 브라우저(Firefox나 Chrome 등)에서 파일을 열고 코드 에디터에서 코드를 살펴보세요. 아니면 각 예제 아래에 있는 "Play" 버튼을 눌러 플레이그라운드에서 직접 실행해 볼 수도 있습니다.

<header>
  <h1>Sample flexbox example</h1>
</header>
<section>
  <article>
    <h2>First article</h2>
    <p>Content…</p>
  </article>
  <article>
    <h2>Second article</h2>
    <p>Content…</p>
  </article>
  <article>
    <h2>Third article</h2>
    <p>Content…</p>
  </article>
</section>
body {
  font-family: sans-serif;
  margin: 0;
}
header {
  background: purple;
  height: 100px;
}
h1 {
  text-align: center;
  color: white;
  line-height: 100px;
  margin: 0;
}
section {
  zoom: 0.8;
}
article {
  padding: 10px;
  margin: 10px;
  background: aqua;
}
/* Add your flexbox CSS below here */

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

코드를 보면 최상단 제목이 들어간 <header> 요소가 있고, 그 아래에 세 개의 <article>을 포함하는 <section> 요소가 있는 것을 알 수 있습니다. 우리는 이것들을 사용해서 꽤 표준적인 '3단 레이아웃'을 만들어 볼 것입니다.


어떤 요소를 플렉시블 박스로 만들지 지정하기 (Specifying what elements to lay out as flexible boxes)

가장 먼저 해야 할 일은, 어떤 요소들을 플렉시블 박스 형태로 배치할 것인지 선택하는 것입니다. 이를 위해, 영향을 주고 싶은 요소들의 부모(parent) 요소display 속성의 특별한 값인 flex를 설정합니다. 이 예제에서는 <article> 요소들을 나란히 배치하고 싶으므로, 그 부모인 <section>에 설정을 적용합니다:

section {
  display: flex;
}

이 코드는 <section> 요소를 플렉스 컨테이너(flex container)로 만들고, 그 자식 요소들을 플렉스 아이템(flex items)으로 변환합니다. 결과는 다음과 같습니다:

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

이 단 한 줄의 선언만으로 우리가 원하는 대부분의 결과를 얻었습니다. 정말 놀랍지 않나요? 우리는 동일한 크기의 열을 가진 3단 레이아웃을 얻었고, 각 열은 동일한 높이를 가지고 있습니다. 이것은 플렉스 아이템(플렉스 컨테이너의 자식들)에 부여되는 '기본값'들이 바로 이러한 흔한 문제들을 해결하도록 설계되었기 때문입니다.

다시 한번 요약해 볼까요. 어떤 요소에 display: flex를 추가하면 그 요소는 플렉스 컨테이너가 됩니다. 이 컨테이너는 페이지의 다른 요소들과 상호작용할 때는 기본적으로 블록 레벨 콘텐츠(Block-level content)처럼 동작합니다. 그리고 이 요소가 플렉스 컨테이너로 변환되는 순간, 그 직계 자식들은 모두 플렉스 아이템으로 변환되어 배치됩니다.

💡 강사님의 실무 팁!
display: flex를 선언하는 순간 벌어지는 마법을 꼭 기억하세요! 자식 요소들이 자신의 내용물 길이에 상관없이 부모의 높이를 꽉 채우도록 죽 늘어나게 됩니다(stretch). 이게 바로 모든 열의 높이가 똑같아지는 이유입니다.

참고로, display의 외부(outside) 값을 사용해서 컨테이너 자체를 인라인(inline)으로 만들 수도 있습니다 (예: display: inline-flex). 과거의 inline-flex 값 역시 컨테이너를 인라인으로 표시합니다. 이 튜토리얼에서는 컨테이너 내부의 콘텐츠가 어떻게 동작하는지에 집중하겠지만, 인라인과 블록 레이아웃의 차이가 궁금하시다면 display 속성 페이지의 값 비교(value comparison)를 참고해 보세요.


플렉스 모델 (The flex model)

요소들이 플렉스 아이템으로 배치될 때, 이들은 두 개의 축(axes)을 따라 배치됩니다:

왼쪽에서 오른쪽으로 읽는 언어 환경에서 3개의 플렉스 아이템이 플렉스 컨테이너 안에 나란히 배치되어 있습니다. 메인 축(수평)과 교차 축(수직)을 보여주는 다이어그램입니다.

  • 메인 축 (Main axis): 플렉스 아이템들이 나열되는 방향으로 이어지는 축입니다 (예를 들어, 페이지를 가로지르는 행(row) 방향이거나, 아래로 내려가는 열(column) 방향). 이 축의 시작과 끝을 각각 메인 시작(main start)메인 끝(main end)이라고 부릅니다. 메인 시작부터 끝까지의 거리가 바로 메인 크기(main size)입니다.
  • 교차 축 (Cross axis): 플렉스 아이템들이 나열되는 방향과 수직으로 교차하는 축입니다. 이 축의 시작과 끝을 교차 시작(cross start)교차 끝(cross end)이라고 부릅니다. 교차 시작부터 끝까지의 거리가 바로 교차 크기(cross size)입니다.
  • display: flex가 설정된 부모 요소를 플렉스 컨테이너 (flex container)라고 부릅니다 (우리 예제에서는 <section> 요소).
  • 플렉스 컨테이너 안에서 유연한 박스로 배치되는 자식 요소들을 플렉스 아이템 (flex items)이라고 부릅니다 (우리 예제에서는 <article> 요소들).

이 용어들은 앞으로 계속 나올 테니 꼭 머릿속에 담아두세요. 어떤 용어가 헷갈리신다면 언제든 이 다이어그램으로 돌아와 확인하시기 바랍니다.

💡 강사님의 아주 중요한 팁!
"메인 축"과 "교차 축"의 개념은 플렉스박스에서 가장 중요한 뼈대입니다. 가로(row)로 배치할 때는 가로줄이 메인 축이 되고, 세로(column)로 배치할 때는 세로줄이 메인 축이 됩니다. 메인 축이 어디냐에 따라 정렬 속성들이 다르게 작동하니까, 이 축이 머릿속에 그려져야 CSS를 자유자재로 다룰 수 있습니다!


열(Columns)로 할까요, 행(Rows)으로 할까요? (Columns or rows?)

플렉스박스는 메인 축이 어느 방향으로 흐를지(플렉스박스 자식들이 어느 방향으로 배치될지)를 지정할 수 있는 flex-direction이라는 속성을 제공합니다. 기본값은 row로 설정되어 있어서, 여러분의 브라우저 기본 언어가 작동하는 방향(한국어나 영어의 경우 왼쪽에서 오른쪽)으로 아이템들을 한 줄(행)로 배치합니다.

<section> CSS 규칙에 다음 선언을 추가해 보세요:

flex-direction: column;

아이템들이 다시 우리가 어떤 CSS도 추가하지 않았을 때의 모습처럼 세로(열) 방향으로 배치되는 것을 보실 수 있을 겁니다. 다음 내용으로 넘어가기 전에, 방금 추가한 이 선언은 다시 지워주세요!

참고:
row-reversecolumn-reverse 값을 사용하면 플렉스 아이템들을 역방향으로 배치할 수도 있습니다. 이 값들도 꼭 한 번씩 테스트해 보세요! 실무에서 채팅창 구현할 때 아래서부터 쌓아 올리려고 column-reverse를 은근히 자주 씁니다.


줄 바꿈 (Wrapping)

레이아웃에 고정된 너비나 높이가 있는 경우 발생하는 한 가지 문제는, 플렉스박스의 자식들이 결국 컨테이너를 넘쳐흘러(overflow) 레이아웃이 깨지게 된다는 점입니다. 다음 예제에서는 5개의 <article>이 있는데, 이들은 min-width400px로 설정되어 있어서 부모 요소에 다 들어가지 못하고 가로 스크롤이 생겨버립니다.

article {
  min-width: 400px;
  padding: 10px;
  margin: 10px;
  background: aqua;
}
section {
  display: flex;
  flex-direction: row;
  zoom: 0.8;
}

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

자식들이 컨테이너를 부수고 밖으로 튀어나온 것을 볼 수 있죠. 기본적으로, flex-directionrowcolumn으로 설정되어 있으면 브라우저는 어떻게든 모든 플렉스 아이템을 '한 줄(single row/column)'에 다 욱여넣으려고 시도합니다.

이 문제를 고칠 수 있는 방법이 있습니다. <section> 규칙에 다음 선언을 추가해 보세요:

section {
  flex-wrap: wrap;
}

이제 레이아웃이 훨씬 보기 좋게 변한 것을 확인할 수 있습니다:

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

이제 여러 줄(행)이 생겼습니다. 각 행은 무리하지 않고 상식적으로 들어갈 수 있는 만큼의 플렉스박스 자식들을 배치합니다. 공간이 부족해서 넘치는(overflow) 아이템들은 자연스럽게 다음 줄로 떨어집니다.

그리고 여기서 또 한 가지 재미있는 점! flex-direction 값을 row-reverse로 바꿔보세요. 여러 줄의 레이아웃은 그대로 유지되지만, 이번에는 브라우저 창의 반대쪽(오른쪽) 구석부터 시작해서 역방향으로 흐르는 것을 볼 수 있습니다.


flex-flow 축약형 (flex-flow shorthand)

여기서 짚고 넘어갈 만한 점은 flex-directionflex-wrap 두 가지 속성을 하나로 합쳐서 쓸 수 있는 축약형 속성인 flex-flow가 존재한다는 것입니다. 예를 들어, 아래 코드를:

flex-direction: row;
flex-wrap: wrap;

이렇게 한 줄로 바꿀 수 있습니다:

flex-flow: row wrap;

플렉스 아이템의 유연한 크기 조절 (Flexible sizing of flex items)

이제 우리의 첫 번째 예제로 돌아가서, 각 플렉스 아이템이 다른 플렉스 아이템들과 비교해서 '얼마나 많은 공간의 비율(proportion)'을 차지하게 할지 제어하는 방법을 살펴보겠습니다.

여러분의 로컬 코드에서 CSS 맨 아래에 다음 규칙을 추가해 보세요:

article {
  flex: 1;
}

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

이 값은 단위가 없는 비율(proportion) 값으로, 각각의 플렉스 아이템이 메인 축을 따라 사용 가능한 공간을 얼마나 가져갈지를 나타냅니다. 이 경우, 우리는 모든 <article> 요소에 동일한 값(1)을 주었습니다. 이는 여백(margin)이나 패딩(padding) 같은 속성이 계산되고 난 뒤 남은 '여분의 공간(spare space)'을 모든 아이템이 똑같이 균등하게 나누어 가진다는 뜻입니다. 이 비율은 상대적으로 계산되기 때문에, 모든 플렉스 아이템에 400000이라는 값을 주더라도 정확히 똑같이 균등 배분됩니다.

이제 이전 규칙 아래에 다음 규칙을 추가해 보세요:

article:nth-of-type(3) {
  flex: 2;
}

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

이제 새로고침을 해보면, 세 번째 <article>이 다른 두 개보다 두 배나 더 넓은 너비를 차지하는 것을 볼 수 있습니다. 현재 사용할 수 있는 비율 조각은 총 4개(1 + 1 + 2 = 4)입니다. 처음 두 개의 플렉스 아이템은 각각 1조각씩 가지므로 사용 가능한 공간의 1/4씩을 차지합니다. 세 번째 아이템은 2조각을 가지므로 전체 사용 가능 공간의 2/4(즉, 절반)를 차지하게 됩니다.

flex 값 안에 최소 크기(minimum size)를 함께 명시할 수도 있습니다. 기존의 article 규칙을 다음과 같이 업데이트해 보세요:

article {
  flex: 1 100px;
}

article:nth-of-type(3) {
  flex: 2 100px;
}

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

이 코드는 근본적으로 이렇게 말하는 것과 같습니다. "일단 모든 플렉스 아이템에게 최소 100px의 공간을 기본으로 깔아주자. 그러고 나서 남은 여분의 공간을 아까 설정한 비율 조각(1:1:2)에 맞춰서 나누어 갖게 하자." 이렇게 설정하면 공간이 분배되는 방식에 확실한 차이가 생기는 것을 볼 수 있습니다.

💡 강사님의 실무 팁!
"일단 기본으로 이만큼 먹고 시작해, 그리고 남은 걸 비율로 나눠!" 이 개념을 이해하는 것이 Flexbox 크기 조절의 핵심입니다.

모든 플렉스 아이템은 flex 속성을 통해 설정된 최소 너비 100px를 가집니다. 첫 두 개의 아이템은 flex 비율 값이 1이고 세 번째는 2입니다. 이로 인해 플렉스 컨테이너에 남은 자투리 공간은 4개의 조각으로 나뉘고, 세 번째 아이템이 다른 아이템보다 더 많은 공간을 차지하게 되죠.

플렉스박스의 진정한 가치는 바로 이 '유연성(flexibility)'과 '반응성(responsiveness)'에서 드러납니다. 브라우저 창의 크기를 이리저리 늘이고 줄여보거나, <article> 요소를 HTML에 하나 더 추가해 보세요. 레이아웃이 깨지지 않고 찰떡같이 아주 잘 작동하는 것을 볼 수 있습니다!


flex 축약형 vs 개별 속성 (flex: shorthand versus longhand)

flex는 최대 세 가지 다른 값을 한 번에 지정할 수 있는 축약(shorthand) 속성입니다:

  • 위에서 논의했던 단위 없는 비율(팽창) 값입니다. 개별 속성인 flex-grow를 사용하여 따로 지정할 수 있습니다.
  • 두 번째 단위 없는 비율 값인 flex-shrink입니다. 이 값은 플렉스 아이템들이 컨테이너를 넘쳐흐르려고 할 때(공간이 부족할 때) 작동합니다. 넘침(overflow)을 방지하기 위해 각 아이템이 얼마나 수축(shrink)할 것인지를 지정합니다. 이는 플렉스박스의 꽤 고급 기능이므로 이 문서에서는 더 깊이 다루지 않겠습니다.
  • 위에서 논의했던 최소(기본) 크기 값입니다. 개별 속성인 flex-basis를 사용하여 따로 지정할 수 있습니다.

💡 강사님의 실무 팁!
정리하자면 flex: <grow> <shrink> <basis> 순서로 들어갑니다!

  • flex-grow: 남는 공간을 얼마나 당겨올까? (기본값 0)
  • flex-shrink: 공간이 부족할 때 내가 얼마나 양보해서 줄어들까? (기본값 1)
  • flex-basis: 내 본래 덩치(기본 크기)는 얼마로 쳐줄래? (기본값 auto)

(이전에 설정된 무언가를 덮어써야 하는 경우를 제외하고는) 이 개별 속성(longhand)들을 따로 분리해서 사용하는 것은 권장하지 않습니다. 코드가 쓸데없이 길어지고, 헷갈리기 쉽기 때문입니다. 그냥 flex 축약형을 사랑해 주세요!


수평 및 수직 정렬 (Horizontal and vertical alignment)

플렉스박스 기능들을 사용하면 메인 축(main axis)이나 교차 축(cross axis)을 따라 플렉스 아이템들을 자유자재로 정렬할 수 있습니다. 새로운 예제를 통해 이를 살펴봅시다:

<div>
  <button>Smile</button>
  <button>Laugh</button>
  <button>Wink</button>
  <button>Shrug</button>
  <button>Blush</button>
</div>
body {
  font-family: sans-serif;
  width: 90%;
  max-width: 960px;
  margin: 10px auto;
}
div {
  height: 100px;
  border: 1px solid black;
}
button {
  font-size: 18px;
  line-height: 1.5;
  width: 15%;
}
/* Add your flexbox CSS below here */

우리는 이 코드를 깔끔하고 유연한 버튼 바(메뉴 바)로 탈바꿈시킬 것입니다. 지금 당장 결과물을 보면, 컨테이너의 왼쪽 상단 구석에 버튼들이 무식하게 다닥다닥 뭉쳐 있는 것을 볼 수 있습니다.

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

먼저 이 예제를 여러분의 로컬로 복사해 오세요.
그다음, CSS의 맨 아래에 다음 코드를 추가합니다:

div {
  display: flex;
  align-items: center;
  justify-content: space-around;
}

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

새로고침을 해보면, 버튼들이 수평으로나 수직으로나 아주 아름답게 정렬된 것을 볼 수 있습니다! 우리는 방금 추가한 두 개의 속성을 통해 이를 이뤄냈습니다. align-items 속성을 center로 설정하여 플렉스 아이템들을 '교차 축'의 정중앙에 위치시켰고, justify-content 속성을 space-around로 설정하여 '메인 축'을 따라 아이템들을 일정한 간격으로 띄워 놓은 것입니다.

align-items 속성은 플렉스 아이템들이 교차 축(cross axis)에서 어디에 위치할지를 제어합니다 (가로 정렬일 경우 위/아래 정렬).

  • 기본값은 normal이며, 이는 플렉스박스에서 stretch와 동일하게 작동합니다. 이 값은 모든 플렉스 아이템을 부모 컨테이너의 교차 축 방향으로 쭉 늘려(stretch) 꽉 채웁니다. 만약 부모 요소가 교차 축 방향으로 고정된 크기(높이 등)가 없다면, 모든 아이템은 가장 키가 큰(또는 넓은) 아이템의 크기에 맞춰서 똑같이 늘어납니다. 이게 바로 우리가 처음에 만들었던 예제에서 모든 열(column)의 높이가 똑같아진 이유입니다.
  • 우리가 방금 사용한 center 값은 아이템들이 자신의 원래 크기(intrinsic dimensions)를 유지하면서, 교차 축의 한가운데로 오도록 만듭니다. 우리 버튼들이 세로 방향의 정중앙에 위치하게 된 이유죠.
  • 이 밖에도 flex-start, self-start, start (교차 축의 시작점에 붙이기) 그리고 flex-end, self-end, end (교차 축의 끝점에 붙이기) 같은 값들도 사용할 수 있습니다. baseline 값은 모든 아이템의 첫 번째 텍스트 줄 밑바닥(baseline)을 기준으로 나란히 정렬해 줍니다. 전체 목록은 align-items를 참고하세요.

각각의 개별 플렉스 아이템에 align-self 속성을 적용하면, 부모 컨테이너에 설정된 align-items의 규칙을 무시하고 자기 혼자만 튀게 정렬할 수도 있습니다. 예를 들어 CSS에 다음 코드를 추가해 보세요:

button:first-child {
  align-self: flex-end;
}

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

첫 번째 버튼(Smile)만 아래쪽 구석으로 툭 떨어져 버렸죠? 효과를 확인하셨다면 이 코드는 다시 지워주세요.

justify-content는 플렉스 아이템들이 메인 축(main axis)을 따라 어디에 위치할지를 제어합니다 (가로 정렬일 경우 좌/우 정렬, 여백 분배).

  • 기본값은 normal이며 이는 start처럼 동작합니다. 즉, 메인 축의 시작점(보통 왼쪽)으로 모든 아이템을 몰아넣습니다.
  • endflex-end를 사용하면 끝점(오른쪽)으로 몰아넣습니다.
  • leftright 값은 글자 쓰기 방향(writing mode)에 따라 startend로 취급됩니다.
  • center를 사용하면 메인 축의 정중앙에 아이템들을 모아줍니다.
  • 우리가 위에서 사용한 space-around는 아주 유용합니다. 메인 축을 따라 모든 아이템을 균등하게 분배하되, 양쪽 끝에도 약간의 여백(아이템 간 여백의 절반 크기)을 남겨줍니다.
  • space-between이라는 친구도 있는데, 이는 space-around와 거의 똑같지만 양쪽 맨 끝 요소는 벽에 딱 붙이고 아이템 '사이'에만 여백을 골고루 분배한다는 점이 다릅니다.

참고로, 플렉스박스 레이아웃에서는 justify-items라는 속성은 아예 무시됩니다 (Grid에서만 쓰여요).

다음 과정으로 넘어가기 전에, 꼭 이 값들을 이리저리 수정해 보며 어떻게 작동하는지 눈으로 직접 익혀보시기를 강력히 권장합니다!

💡 강사님의 실무 팁!
"가운데 정렬 어떻게 해요?"
이 질문의 영원한 해답. 부모 요소에 display: flex; justify-content: center; align-items: center; 이 3종 세트면 세상의 어떤 아이템이든 완벽한 정중앙에 놓을 수 있습니다!


플렉스 아이템 순서 바꾸기 (Ordering flex items)

플렉스박스는 HTML 소스 코드의 순서를 전혀 건드리지 않고도 화면에 렌더링되는 시각적 순서를 바꿀 수 있는 엄청난 기능을 제공합니다. 전통적인 레이아웃 방식으로는 상상도 할 수 없는 일이었죠.

여러분의 버튼 바 예제 CSS에 다음 코드를 추가해 보세요:

button:first-child {
  order: 1;
}

새로고침을 해보면, 가장 앞에 있던 "Smile" 버튼이 메인 축의 가장 맨 끝(맨 오른쪽)으로 휙 이동한 것을 볼 수 있습니다. 원리가 무엇일까요?

  • 기본적으로 모든 플렉스 아이템은 order 속성 값이 0으로 설정되어 있습니다.
  • 지정된 order 값이 더 큰 아이템일수록, 낮은 order 값을 가진 아이템들보다 화면에서 더 나중에(뒤에) 나타납니다. (그래서 1을 준 Smile 버튼이 0인 다른 버튼들을 밀어내고 맨 뒤로 간 것입니다.)
  • 만약 order 값이 서로 똑같다면, HTML 소스 코드에 작성된 순서대로 나타납니다. 따라서 4개의 아이템에 순서대로 2, 1, 1, 0 이라는 order 값을 주었다면, 화면에는 4번째(0), 2번째(1), 3번째(1), 1번째(2) 아이템 순으로 표시될 것입니다.
  • (동점인 2번째와 3번째 아이템은 HTML 소스 코드에서 2번째가 먼저 나오므로 그 순서를 유지합니다.)

음수(negative) 값을 주어서 0인 아이템들보다 더 앞으로 보낼 수도 있습니다. 예를 들어, 다음 규칙을 쓰면 "Blush" 버튼이 맨 앞(메인 축의 시작점)으로 튀어나오게 됩니다:

button:last-child {
  order: -1;
}

⚠️ 주의: order 속성으로 눈에 보이는 '시각적 순서'를 바꿀 수는 있지만, 키보드의 Tab 키를 눌렀을 때 포커스가 이동하는 순서나 스크린 리더가 읽어주는 순서는 여전히 HTML 코드에 작성된 순서를 그대로 따릅니다. 시각적 순서와 논리적(키보드) 순서가 꼬이게 되면 시각 장애인이나 키보드 사용자들의 사용성(Accessibility)에 심각한 악영향을 미칠 수 있으므로 정말 신중하게 사용해야 합니다!


중첩된 플렉스 박스 (Nested flex boxes)

플렉스박스를 사용하면 꽤나 복잡한 레이아웃도 뚝딱 만들어 낼 수 있습니다. 어떤 플렉스 아이템을 선택해서 그 녀석에게도 display: flex를 줘서 또 다른 플렉스 컨테이너로 만드는 것(중첩, Nesting)은 완벽하게 훌륭한 방법입니다.

<header>
  <h1>Complex flexbox example</h1>
</header>
<section>
  <article>
    <h2>First article</h2>
    <p>Content…</p>
  </article>
  <article>
    <h2>Second article</h2>
    <p>Content…</p>
  </article>
  <article>
    <div>
      <button>Smile</button>
      <button>Laugh</button>
      <button>Wink</button>
      <button>Shrug</button>
      <button>Blush</button>
    </div>
    <div>
      <p>Paragraph one content…</p>
    </div>
    <div>
      <p>Paragraph two content…</p>
    </div>
  </article>
</section>
body {
  font-family: sans-serif;
  margin: 0;
}
header {
  background: purple;
  height: 100px;
}
h1 {
  text-align: center;
  color: white;
  line-height: 100px;
  margin: 0;
}
article {
  padding: 10px;
  margin: 10px;
  background: aqua;
}
section {
  display: flex;
  zoom: 0.8;
}
article {
  flex: 1 170px;
}
article:nth-of-type(3) {
  flex: 3 170px;
  display: flex;
  flex-flow: column;
}
article:nth-of-type(3) div:first-child {
  flex: 1 100px;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  justify-content: space-around;
}
button {
  flex: 1 auto;
  margin: 5px;
  font-size: 18px;
  line-height: 1.5;
}

MDN Playground에서 직접 예제 코드 만져보기 (Run example in MDN Playground)

이 복잡한 레이아웃을 보면, 플렉스 아이템이면서 동시에 플렉스 컨테이너인 요소들이 섞여 있습니다. 이 HTML의 뼈대를 그려보면 이렇습니다. <section> 안에 세 개의 <article>이 있고, 세 번째 <article> 안에는 다시 세 개의 <div>가 있으며, 그중 첫 번째 <div> 안에 다섯 개의 <button>이 들어있죠:

section - article
          article
          article - div - button
                    div   button
                    div   button
                          button
                          button

이 레이아웃을 완성하기 위해 우리가 사용한 CSS 코드를 분석해 볼까요.

가장 먼저, <section>의 자식들(<article>들)을 플렉스 박스로 배치합니다.

section {
  display: flex;
}

그다음, <article> 요소들 자체에 flex 비율 값을 줍니다. 여기서 두 번째 규칙을 눈여겨보세요. 우리는 세 번째 <article>이 다른 아이템들보다 3배 더 많은 비율을 차지하게 함과 동시에, 그 자신을 플렉스 컨테이너로 만들고(display: flex), 자식 요소들(<div>들)을 세로 열(flex-flow: column)로 배치하도록 지시했습니다.

article {
  flex: 1 100px;
}

article:nth-of-type(3) {
  flex: 3 100px;
  display: flex;
  flex-flow: column;
}

다음으로 세 번째 <article> 안의 첫 번째 자식 <div>를 선택합니다. 먼저 flex: 1 100px;을 주어 요소의 최소 높이를 100px로 확보한 뒤, 이 <div> 마저도 자식들(버튼들)을 품는 플렉스 컨테이너로 만듭니다. 이번에는 가로로 나열하되 공간이 부족하면 줄 바꿈이 되도록 flex-flow: row wrap;을 주었고, 앞서 배운 버튼 바 예제처럼 align-items: center;justify-content: space-around;로 중앙 정렬과 균등 여백 분배를 해 주었습니다.

article:nth-of-type(3) div:first-child {
  flex: 1 100px;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  justify-content: space-around;
}

마지막으로 각 버튼에 크기 조절 속성을 넣습니다. 이번에는 flex 값을 1 auto로 주었어요. 이 설정은 엄청나게 매력적인 결과를 만들어 내는데, 브라우저 창의 너비를 쭉 늘였다 줄였다 해보시면 그 진가를 알 수 있습니다. 버튼들은 자신들이 차지할 수 있는 모든 여분 공간을 쭉쭉 빨아들여 늘어납니다. 좁아져서 더 이상 한 줄에 편하게 있을 수 없으면 다음 줄로 톡 떨어지면서 또 남은 공간을 균등하게 차지하죠!

button {
  flex: 1 auto;
  margin: 5px;
  font-size: 18px;
  line-height: 1.5;
}

💡 강사님의 실무 팁!
중첩 레이아웃은 실무의 핵심입니다! 웹사이트의 거대한 레이아웃 뼈대도 Flex(또는 Grid)로 잡고, 그 안의 작은 컴포넌트(예: 프로필 사진과 이름이 가로로 배치된 카드)도 Flex로 잡습니다. "박스를 가로로, 또는 세로로 나열하고 싶다?" 무조건 display: flex;부터 치고 시작하세요!


요약 (Summary)

이것으로 플렉스박스(Flexbox)의 기본기에 대한 기나긴 여행을 마쳤습니다. 플렉스박스의 매력을 충분히 느끼셨기를 바라며, 앞으로 학습을 진행하시면서 이 강력한 도구를 이리저리 가지고 놀아보시길 바랍니다.

다음 문서에서는 오늘 배운 이 지식들을 얼마나 잘 이해하고 기억하고 있는지 스스로 점검해 볼 수 있는 재미있는 테스트가 준비되어 있습니다. 준비되셨나요?


같이 보기 (See also)


MDN 개선에 도움을 주세요 (Help improve MDN)

기여하는 방법 알아보기 (Learn how to contribute)

이 페이지의 마지막 수정일은 Dec 19, 2025 이며, MDN 기여자들(MDN contributors)에 의해 작성되었습니다.

정말 긴 내용이었지만, 끝까지 잘 따라오셨습니다! Flexbox는 머리로 외우는 것보다 직접 박스들을 띄워보고 움직여보는 게 백 번 낫습니다. "Flexbox Froggy" 꼭 한 번 해보시고, 궁금한 점이 생기면 언제든 질문해 주세요!

profile
프론트에_가까운_풀스택_개발자

0개의 댓글