CSS 플렉스박스 가이드 - 정렬과 배치를 한 번에 끝내는 실전 정리
float와 position으로 레이아웃 짜느라 고생하셨나요. CSS 플렉스박스 가이드로 가로 세로 정렬, 간격, 반응형 배치까지 속성 하나하나 예제와 함께 익혀보세요.
![]()
가운데 정렬 한 번 하려고 margin: auto에 line-height까지 동원했던 기억, 다들 있으실 겁니다. 세로 가운데 정렬은 또 왜 그렇게 안 되는지 답답했죠. 플렉스박스를 제대로 익히면 이런 작업이 속성 두세 줄로 끝납니다. 어렵게 외울 것도 없습니다. 컨테이너에 무엇을 주고 아이템에 무엇을 주는지, 그 구분만 잡으면 됩니다.
왜 플렉스박스를 써야 할까
플렉스박스(Flexbox)는 1차원 레이아웃을 위한 CSS 모듈입니다. 가로 한 줄 또는 세로 한 줄에 들어가는 요소들을 정렬하고 간격을 배분하는 데 특화돼 있습니다. 2차원 격자 배치가 필요하면 Grid를 쓰지만, 메뉴바, 카드 나열, 버튼 그룹처럼 한 방향으로 늘어놓는 경우는 대부분 플렉스박스가 정답입니다.
과거에는 float와 clearfix, position absolute를 조합해 레이아웃을 잡았습니다. 코드가 길어지고 디버깅도 까다로웠죠. 플렉스박스는 2017년 무렵부터 모든 주요 브라우저에서 안정적으로 지원되기 시작했고, 지금은 Internet Explorer를 신경 쓸 일이 거의 없어 부담 없이 사용할 수 있습니다.
플렉스박스의 핵심은 "컨테이너가 자식들의 배치를 책임진다"는 발상입니다. 자식 하나하나를 일일이 미는 게 아니라, 부모가 정렬 규칙을 선언하면 나머지는 알아서 따라옵니다.
기본 개념 - 컨테이너와 아이템
플렉스박스는 두 개의 역할로 나뉩니다. display: flex를 선언한 부모가 플렉스 컨테이너이고, 그 직계 자식들이 플렉스 아이템입니다. 속성도 이 두 곳에 나눠서 줍니다. 컨테이너 속성과 아이템 속성을 헷갈리면 적용이 안 되니 이 구분을 먼저 익히세요.
방향을 가리키는 용어도 두 가지입니다. 아이템이 배치되는 방향을 주축(main axis), 그에 수직인 방향을 교차축(cross axis)이라고 부릅니다. 기본값에서는 주축이 가로, 교차축이 세로입니다. flex-direction을 바꾸면 이 축도 함께 회전한다는 점이 중요합니다.
컨테이너 속성 6가지
컨테이너에 주는 속성만 제대로 알아도 레이아웃의 80퍼센트는 해결됩니다. 가장 많이 쓰는 여섯 가지를 정리했습니다.
| 속성 | 역할 | 주요 값 |
|---|---|---|
| flex-direction | 주축 방향 설정 | row, column, row-reverse |
| justify-content | 주축 정렬 | center, space-between, flex-start |
| align-items | 교차축 정렬 | center, stretch, flex-end |
| flex-wrap | 줄바꿈 허용 여부 | nowrap, wrap |
| gap | 아이템 사이 간격 | 16px, 1rem 등 |
| align-content | 여러 줄의 교차축 정렬 | center, space-around |
흔히 말하는 완벽한 가운데 정렬은 이 조합 하나면 끝납니다.
- display: flex - 컨테이너 선언
- justify-content: center - 가로 가운데
- align-items: center - 세로 가운데
예전에 그렇게 안 되던 세로 가운데 정렬이 이 세 줄로 해결됩니다. gap 속성도 기억해 두세요. 아이템마다 margin을 주던 방식보다 간결하고, 마지막 요소의 불필요한 여백 문제도 생기지 않습니다.
아이템 속성과 flex 단축
아이템에 주는 속성 중 핵심은 flex 단축 속성입니다. flex-grow, flex-shrink, flex-basis 세 가지를 한 번에 지정합니다.
flex 세 값의 의미
- flex-grow - 남는 공간을 얼마나 차지할지 (기본 0)
- flex-shrink - 공간이 부족할 때 얼마나 줄어들지 (기본 1)
- flex-basis - 기본 크기 (기본 auto)
실무에서는 flex: 1을 가장 많이 씁니다. 형제 아이템들이 남는 공간을 똑같이 나눠 가지라는 뜻입니다. 사이드바는 고정 너비로 두고 본문만 늘어나게 하려면, 본문에만 flex: 1을 주고 사이드바에는 고정 width를 지정하면 됩니다.
아이템별로 교차축 정렬을 다르게 하고 싶다면 align-self를 사용합니다. 컨테이너의 align-items를 개별 아이템에서 덮어쓰는 속성입니다.
실전 레이아웃 패턴
이론보다 자주 쓰는 패턴을 손에 익히는 게 빠릅니다. 아래 세 가지는 거의 모든 페이지에 등장합니다.
1. 상단 네비게이션 바
컨테이너에 display: flex; justify-content: space-between; align-items: center를 주면 양 끝 배치에 세로 가운데 정렬까지 한 번에 됩니다. 메뉴 항목 사이 간격은 gap으로 조절합니다.
2. 반응형 카드 그리드
flex-wrap: wrap과 gap을 함께 쓰고, 각 카드에 flex: 1 1 300px처럼 지정하면 화면이 좁아질 때 카드가 자동으로 다음 줄로 넘어갑니다. 최소 너비 300px를 보장하면서 남는 공간은 균등하게 채웁니다.
3. 푸터 하단 고정
body나 래퍼에 min-height: 100vh; display: flex; flex-direction: column을 주고, 본문 영역에 flex: 1을 적용하면 콘텐츠가 짧아도 푸터가 화면 맨 아래에 붙습니다. 이른바 sticky footer 문제를 깔끔하게 해결하는 방식입니다.
웹 도구를 직접 만들다 보면 입력값을 다른 형식으로 바꿔야 할 때가 많습니다. 예를 들어 이미지나 텍스트를 문자열로 변환할 때 쓰는 Base64 인코더 같은 도구의 화면도 입력칸과 결과칸을 양옆으로 배치한 전형적인 플렉스 레이아웃입니다. 입력 영역과 결과 영역에 각각 flex: 1을 주면 어느 한쪽으로 치우치지 않고 균형 잡힌 화면을 만들 수 있습니다.
자주 하는 실수와 해결법
플렉스박스를 처음 쓸 때 막히는 지점은 대체로 정해져 있습니다.
- 속성이 안 먹힐 때 - 컨테이너 속성을 아이템에 줬거나 그 반대인 경우가 대부분입니다. justify-content는 부모에, align-self는 자식에 준다는 점을 다시 확인하세요.
- 아이템이 찌그러질 때 - flex-shrink 기본값이 1이라 공간이 부족하면 줄어듭니다. 줄이고 싶지 않으면 flex-shrink: 0을 줍니다.
- 줄바꿈이 안 될 때 - flex-wrap 기본값이 nowrap입니다. wrap을 명시해야 다음 줄로 넘어갑니다.
계산이 들어가는 화면, 예를 들어 입력값에 따라 결과가 실시간으로 바뀌는 대출 계산기 같은 페이지도 입력 폼과 결과 표시 영역을 플렉스박스로 나누면 반응형 대응이 한결 수월합니다. 폼 영역은 고정, 결과 영역은 flex: 1로 두는 식입니다.
지금 만들고 있는 페이지에서 가장 자주 쓰는 패턴부터 손에 익히세요. 네비게이션 바 양 끝 정렬, 카드 반응형 배치, 이 두 가지만 자유자재로 쓸 수 있어도 레이아웃 작업 속도가 눈에 띄게 빨라집니다. 그다음 flex 단축 속성으로 비율을 다루는 감각을 더하면 됩니다.