목차12개 항목
출처와 참고
Rachel Andrew의 「플렉스박스 플렉스 컨테이너를 만들 때 무슨 일이 벌어질까?」(2018.09, 웹액츄얼리 번역)과 곽빵의 「flexbox에서 가변요소의 자식 width가 부모 width를 넘을 때」(2021.09)를 바탕으로 재구성하고, web.dev 「Learn CSS」 강좌의 Layout·Flexbox 모듈로 보강한 노트다. float가 놓이는 규칙과 옛 float 해제법은 「Frontend_TIL: Float 배치되는 과정」·「float 해제 방법」·「float으로 레이아웃 구성 및 이해」을 CSS 명세로 확인해 보강했다.
블록은 위에서 아래로, 인라인은 왼쪽에서 오른쪽으로 쌓이는 Normal Flow만으로는 "옆으로 나란히", "가운데 정렬", "남은 공간 나눠 갖기" 같은 레이아웃을 만들기 어렵다. 예전에는 float로 이를 해결했고, 지금은 대부분 Flexbox와 Grid로 처리한다.
Float
박스를 왼쪽 또는 오른쪽으로 띄워, 텍스트 같은 인라인 요소들이 그 주변을 감싸도록(wrapping) 한다. 원래 신문처럼 이미지 옆에 글이 흐르게 하려고 만든 속성이다.

.left { float: left; } /* none(기본) | left | right */- float된 박스는
display가 블록 계열로 바뀌고(inline이어도width·height가 먹는다), 너비는 내용만큼 줄어든다. - 블록 박스는 float를 못 본 척 그 아래로 깔리지만, 그 안의 줄 상자(글)만 float를 피해 옆으로 흐른다. 그래서 float 뒤 블록의 배경은 float 밑으로 들어가고 글자만 비켜 선다.
float가 놓이는 규칙
float는 「같은 방향으로 가능한 한 위, 가능한 한 바깥쪽」에 놓이지만 몇 가지 제약을 받는다.
| 규칙 | 결과 |
|---|---|
| 먼저 나온 float보다 위로 올라가지 못한다 | 소스 순서가 뒤인 float의 윗변은 앞선 float의 윗변보다 높을 수 없다 |
| 남은 줄 폭에 안 들어가면 아래로 밀린다 | 폭 300px 컨테이너에 100px float 다음 210px float가 오면 두 번째는 첫째 아래 줄로 내려간다 |
| 밀려난 자리 위로는 아무것도 못 간다 | 위 예에서 뒤따르는 20px짜리 float: right는 첫 줄 오른쪽에 빈 공간이 있어도 그 줄로 못 올라가고, 밀려난 float와 같은 줄 오른쪽에 붙는다 |
| 왼쪽 float와 오른쪽 float는 서로 겹치지 않는다 | 한 줄에 둘이 다 안 들어가면 뒤에 나온 쪽이 아래로 밀린다 |

float로 여러 칸을 늘어놓으면 높이가 다른 칸 하나가 뒤의 칸들을 엉뚱한 줄에 걸리게 만든다. 칸 배치는 플렉스·그리드로 한다.
float를 부모 안에 담기
float된 요소는 Normal Flow에서 벗어나 떠 있기 때문에, 이후 요소가 그 밑으로 파고들거나 부모가 높이를 잃는다(float만 담은 부모의 높이는 0이다). 부모에 display: flow-root를 주면 부모가 새 블록 서식 맥락(BFC)을 만들어 float를 안에 담는다. 높이가 float까지 늘어나고, 바깥 요소와도 섞이지 않는다.
.media { display: flow-root; } /* 안의 float를 품는다 */
.after-float { clear: both; } /* 특정 요소만 float 아래로 내릴 때 */flow-root 전에는 여러 우회법을 썼다. 모두 부작용이 있어 새 코드에는 쓰지 않는다.
| 옛 방법 | 원리 | 부작용 |
|---|---|---|
부모도 float | float는 BFC를 만들어 자식 float를 감싼다 | 부모가 흐름에서 빠지고 너비가 줄어 문제가 한 단계 위로 옮겨 간다 |
부모에 display: inline-block | inline-block도 BFC를 만든다 | 부모가 내용 폭으로 줄고 인라인처럼 놓인다 |
부모에 overflow: hidden | visible이 아닌 overflow가 BFC를 만든다 | 밖으로 나가야 할 그림자·드롭다운이 잘린다 |
마지막 자식으로 빈 <div style="clear: both"> | 빈 요소가 float 아래로 내려가며 부모를 늘린다 | 의미 없는 마크업이 남는다 |
clearfix(::after) | 가상 요소를 빈 블록으로 만들어 clear | 동작은 맞지만 flow-root 한 줄로 대체된다 |
/* 과거의 clearfix. ::after는 기본이 인라인이라 clear가 먹지 않아 block으로 바꾸고, content가 있어야 생긴다 */
.clearfix::after { content: ""; display: block; clear: both; }Flexbox·Grid 등장 이후 float로 레이아웃을 짜는 일은 크게 줄었고, 지금은 본래 용도(글 감싸기)에 주로 쓴다. BFC가 무엇이고 어떤 값이 만드는지는 박스 모델의 BFC에 있다.
Flexbox

행 또는 열 한 방향으로 아이템을 배치하는 1차원 레이아웃 모델이다. 수동으로 값을 계산하지 않아도 정렬과 공간 분배를 해 준다.
- Flex Container(부모):
display: flex또는inline-flex를 준 요소 - Flex Item(자식): 컨테이너 안의 박스들
- main axis(주축): 아이템이 나열되는 방향 / cross axis(교차축): 주축에 수직인 방향
display: flex는 display: block flex의 줄임이다. 바깥쪽은 블록이라 컨테이너 자신은 일반 블록처럼 놓이고, 안쪽은 flex라 자식이 플렉스 아이템이 된다. inline-flex는 inline flex다. 아무것도 더 쓰지 않으면 아래 표의 초깃값이 동작한다.
컨테이너 속성
| 분류 | 속성 | 초깃값 | 설명 |
|---|---|---|---|
| 배치 | flex-direction | row | 주축 방향: row, row-reverse, column, column-reverse. row는 인라인 방향이라 가로쓰기·왼→오면 왼쪽부터, RTL이면 오른쪽부터, 세로쓰기면 위부터 나열된다 |
| 배치 | flex-wrap | nowrap | 넘칠 때 줄바꿈 여부. nowrap은 한 줄에 욱여넣는다 |
| 배치 | flex-flow | flex-direction과 flex-wrap의 축약. 예: flex-flow: row wrap; | |
| 공간 나누기 | justify-content | flex-start | 주축 방향 공간 분배. 남는 공간이 없으면 어떤 값이든 효과가 없다 |
| 공간 나누기 | align-content | normal | 교차축 방향 공간 분배(여러 줄일 때만 의미 있음) |
| 정렬 | align-items | stretch | 모든 아이템을 교차축 기준으로 정렬. 기본은 가장 높은 아이템에 맞춰 모두 늘어난다 |
| 간격 | gap (row-gap, column-gap) | normal(0) | 아이템 사이 간격. 모든 주요 브라우저가 플렉스에서도 지원해, 아이템마다 margin을 주고 마지막 것만 빼는 우회가 필요 없다 |

row-reverse, column-reverse는 순서를 바꾸는 것이 아니라 주축의 시작점(main-start)을 반대편으로 옮길 뿐이다. 화면 순서가 HTML 선언 순서와 달라져도 스크린 리더·키보드 탐색 순서는 소스 그대로라 어긋날 수 있다(접근성 주의). 행과 열이 쓰기 모드를 따르는 원리는 쓰기 모드와 논리적 속성에 있다.
justify-content / align-content 값

| 값 | 의미 |
|---|---|
flex-start / flex-end | 축의 시작점 / 끝으로 모음 |
center | 가운데로 모음 |
space-between | 양 끝을 붙이고 아이템 사이 간격을 균등하게 |
space-around | 각 아이템 둘레에 같은 여백(양 끝 여백은 사이 간격의 절반) |
space-evenly | 양 끝을 포함한 모든 간격을 균등하게 |
align-items / align-self 값

| 값 | 의미 |
|---|---|
stretch | 교차축 방향으로 컨테이너를 가득 채움 |
flex-start / flex-end | 교차축의 시작 / 끝 |
center | 가운데 |
baseline | 텍스트 기준선을 맞춤 |
아이템 속성
| 속성 | 초깃값 | 설명 |
|---|---|---|
align-self | auto | 개별 아이템의 교차축 정렬. 컨테이너가 아니라 아이템에 준다 |
flex-grow | 0 | 남은 공간을 나눠 받는 비율. 초깃값이면 공간이 남아도 커지지 않는다 |
flex-shrink | 1 | 공간이 부족할 때 줄어드는 비율. 초깃값이면 모자랄 때 줄어든다 |
flex-basis | auto | 늘거나 줄기 전의 기본 크기. 크기를 정하지 않았으면 max-content(한 줄로 늘였을 때 크기)에서 출발 |
flex | 0 1 auto | grow shrink basis 축약. 예: flex: 1(= 1 1 0%) |
order | 0 | 배치 순서(작을수록 앞). HTML 순서는 그대로다 |
flex 축약형에는 자주 쓰는 키워드가 있다.
| 값 | 풀어 쓰면 | 결과 |
|---|---|---|
flex: initial | 0 1 auto | 초깃값. 늘지 않고, 모자라면 줄어든다 |
flex: auto | 1 1 auto | 내용 크기(max-content)로 먼저 놓은 뒤 남는 공간을 나눈다. 내용이 큰 아이템이 더 커진다 |
flex: 1 | 1 1 0% | 기본 크기를 0으로 보고 전체 공간을 나눈다. 내용과 상관없이 같은 크기 |
flex: none | 0 0 auto | 늘지도 줄지도 않는다. 정렬 기능만 쓰고 싶을 때 |
flex: 2 | 2 1 0% | 다른 아이템이 flex: 1이면 두 배를 받는다. 1·2·3이면 공간을 6으로 나눠 1:2:3 |
줄어들 때는 flex-shrink 값에 기본 크기를 곱한 비율로 줄어든다. 내용이 많은 아이템은 덜 줄고 짧은 아이템이 먼저 사라지지 않는다. 그래서 따로 크기를 주지 않아도 내용에 비례해 공간을 나눠 갖는다. 이것이 플렉스박스를 쓰는 핵심 이유다.
플렉스 줄과 정렬
flex-wrap: wrap으로 줄이 여러 개가 되면 각 줄이 독립된 플렉스 컨테이너처럼 공간을 나눈다. 2번째 줄 아이템을 1번째 줄 아이템과 세로로 맞출 수 없다. 이것이 플렉스박스가 1차원인 이유이고, 행·열을 함께 맞추려면 그리드를 쓴다.- 감싸기 전 아이템은
min-content크기까지 줄어든 뒤에야 넘친다. align-content의 초깃값은normal(플렉스에서는stretch처럼 동작)이라 여러 줄이 컨테이너 높이를 나눠 갖는다. 남는 공간이 있어야 효과가 있으니 컨테이너에block-size를 준다.place-content: <align-content> <justify-content>는 두 값을 한 줄로 쓴다. 값 하나면 둘 다 같다.flex-direction: column에서justify-content가 동작하려면 컨테이너에 높이가 있어야 한다.- 플렉스에는
justify-self가 없다. 주축에서 아이템은 묶음으로 움직이기 때문이다. 그룹을 나누려면 auto margin을 쓴다. auto margin은 그 방향의 남는 공간을 모두 흡수한다.
.toolbar { display: flex; gap: .5rem; }
.toolbar .spacer-start { margin-inline-start: auto; } /* 이 아이템부터 오른쪽(인라인 끝)으로 밀린다 */자주 쓰는 패턴: 가운데 정렬
.center {
display: flex;
justify-content: center; /* 가로(주축) */
align-items: center; /* 세로(교차축) */
}박스 정렬 속성은 플렉스 전용이 아니다. 블록 컨테이너에서도 align-content: center로 자식을 세로 가운데 놓을 수 있다. Chrome 123, Firefox 125, Safari 17.4부터 모든 주요 브라우저가 지원한다(Baseline 2024). 과거에는 정렬만 하려고 컨테이너를 플렉스로 바꿨다.
.hero { min-block-size: 50vh; align-content: center; } /* display: flex 없이 세로 가운데 */함정: flex 아이템이 컨테이너를 넘칠 때
flex: 1인 아이템 안에 긴 한 줄 텍스트를 넣고 말줄임(…)을 걸었는데, 말줄임은 안 되고 텍스트가 컨테이너 밖으로 삐져나오는 경우가 있다.
.container { display: flex; width: 540px; }
.col-1 { width: 200px; }
.col-2 {
flex: 1;
min-width: 0; /* 이 줄이 없으면 아래 말줄임이 동작하지 않는다 */
}
.col-2 p {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}| 증상 | 원인 | 해결 |
|---|---|---|
overflow: hidden·text-overflow: ellipsis가 안 먹고 아이템이 컨테이너보다 넓어진다 | flex 아이템의 min-width 기본값이 0이 아니라 auto다. auto는 "콘텐츠 최소 크기보다 작아지지 않는다"는 뜻이라, 줄바꿈 없는 긴 텍스트만큼 아이템이 늘어난다. 이 최소 크기 제약이 flex-basis보다 우선한다 | 아이템에 min-width: 0 |
말줄임이 안 된다 = 요소 너비가 제한되지 않았다는 신호다. 다른 해법과 비교하면 다음과 같다.
| 방법 | 평가 |
|---|---|
아이템에 min-width: 0 | 권장. 원인을 직접 고친다 |
컨테이너에 overflow: hidden | 넘친 부분을 잘라 숨길 뿐이라 의도와 다른 결과가 나올 수 있다 |
아이템에 max-width: calc(100vw - 고정폭) | 레이아웃 수치에 묶여 깨지기 쉽다. 비추천 |
flex-direction: column이면 같은 문제가 높이에서 생기므로 min-height: 0을 준다.
다단 레이아웃
국가 목록처럼 긴 목록이나 신문 기사처럼 글이 한 단에서 다음 단으로 이어 흘러야 하면 다단(multicolumn) 레이아웃을 쓴다. 플렉스·그리드로 만든 열은 서로 독립된 칸이라 내용이 이어 흐르지 않는다.
.countries { column-count: 2; column-gap: 1em; } /* 단 개수 고정 */
.articles { column-width: 260px; column-gap: 1em; } /* 최소 단 너비: 공간에 따라 단 수가 자동으로 바뀐다 */
.articles h2 { column-span: all; } /* 제목은 모든 단을 가로질러 */
.articles figure { break-inside: avoid; } /* 그림이 단 사이에서 쪼개지지 않게 */column-width만 주면 미디어 쿼리 없이 반응형이 된다. 단 높이가 화면보다 길면 독자가 위아래로 오가며 읽어야 하므로, 화면에서는 짧은 목록에 주로 쓴다.
Flexbox와 Grid
Flexbox는 한 방향, Grid는 행과 열을 동시에 다룬다. 어느 쪽을 고를지는 CSS 그리드 레이아웃의 선택 기준표에 있다. React Native의 레이아웃도 Flexbox 기반이다(React Native 스타일링 참고).
핵심 정리
- float는 Normal Flow를 벗어난다. 부모에
display: flow-root를 주면 float를 담는다. 레이아웃 용도로는 거의 쓰지 않는다. - Flexbox: 부모에
display: flex, 주축은justify-content, 교차축은align-items. align-self,flex-grow,order는 아이템에 주는 속성이다.- 초깃값만으로도 아이템은 내용에 비례해 공간을 나눠 갖는다.
-reverse는 시작점만 옮긴다. - 같은 크기로 나누려면
flex: 1, 내용 크기 기반이면flex: auto, 고정이면flex: none. - 아이템 하나를 떼어 놓을 땐
justify-self대신 auto margin. - 글을 여러 단으로 이어 흘리려면 다단 레이아웃(
column-width). - flex 아이템의
min-width기본값은auto다. 긴 텍스트 때문에 아이템이 넘치면min-width: 0을 준다.
관련 노트: CSS 그리드 레이아웃, 쓰기 모드와 논리적 속성, 박스 모델과 display, CSS 오버플로와 스크롤: 넘침 처리와 스크롤 스냅, CSS가 동작하는 방식: 핵심 개념과 픽셀이 되기까지, DevTools로 DOM과 CSS 다루기
더 읽을거리: 게임과 실험 도구로 익히기, Flexbox Froggy, flexbox.help(속성을 바꿔 보며 결과 확인)
원본 기록10
- 원문 (새 창) heewon26.tistory.com/298
- 원문 (새 창) webactually.com/2018/09/18/플렉스박스-플렉스-컨테이너를-만들-때-무슨-일이-벌/
- 원문 (새 창) developer.mozilla.org/en-US/docs/Web/CSS/gap
- 원문 (새 창) developer.mozilla.org/en-US/docs/Web/CSS/display#flow-root
- 원문 (새 창) web.dev/learn/css/flexbox
- 원문 (새 창) web.dev/learn/css/layout
- 원문 (새 창) developer.mozilla.org/en-US/docs/Web/CSS/align-content
- GitHub 원문 (새 창) github.com/AI-Dev-Lex-Kim/Frontend_TIL/blob/master/CSS/float 해제 방법.md
- GitHub 원문 (새 창) github.com/AI-Dev-Lex-Kim/Frontend_TIL/blob/master/CSS/Float 배치되는 과정.md
- GitHub 원문 (새 창) github.com/AI-Dev-Lex-Kim/Frontend_TIL/blob/master/CSS/float으로 레이아웃 구성 및 이해.md