CSS 플렉스박스 생성기 가이드 — 시각적으로 레이아웃 만들기
📷 Sai Kiran Anagani / PexelsCSS 플렉스박스 생성기 가이드 — 시각적으로 레이아웃 만들기
CSS Flexbox를 시각적으로 배우세요. flex-direction, justify-content, align-items 등 핵심 속성을 실시간 생성기와 예제로 이해합니다.
CSS 레이아웃은 오랫동안 프론트엔드 개발자들의 골칫거리였다. float과 clear를 조합하고, position: absolute로 강제로 위치를 잡고, 수직 가운데 정렬 하나 하려고 줄줄이 핵을 쓰던 시대가 있었다. Flexbox가 등장하기 전까지는.
지금은 Flexbox가 너무 보편화돼서 "이걸 어떻게 모를 수 있지?" 싶겠지만, 막상 속성이 많다 보니 처음 배울 때 헷갈리는 부분이 꽤 있다. 특히 justify-content와 align-items의 축 개념, flex-grow와 flex-shrink의 동작 방식은 실제로 눈으로 보면서 익혀야 제대로 이해된다.
이 글에서는 Flexbox의 핵심 개념부터 실무에서 자주 쓰는 패턴까지 정리해본다.
Flexbox란 무엇인가
Flexbox는 Flexible Box Layout의 줄임말이다. 이름에서 알 수 있듯 컨테이너 안의 아이템들을 유연하게 배치하기 위한 CSS 레이아웃 모델이다.
핵심 개념은 두 가지다. 컨테이너와 아이템.
display: flex를 적용한 요소가 플렉스 컨테이너가 되고, 그 직계 자식 요소들이 플렉스 아이템이 된다. 컨테이너에는 배치 방식을 지정하는 속성들이 붙고, 아이템에는 개별 크기와 동작을 지정하는 속성들이 붙는다.
/* 이것만으로 div.container의 자식 요소들이 가로로 나란히 늘어선다 */
.container {
display: flex;
}
Flexbox는 1차원 레이아웃이다. 행(row)이나 열(column) 방향 중 하나로 아이템을 배치한다. 2차원(행과 열 동시)이 필요하면 CSS Grid를 써야 한다.
축 개념 이해하기
Flexbox를 헷갈리게 만드는 주요 원인 중 하나가 축(axis) 개념이다.
Flexbox에는 두 개의 축이 있다.
- 주 축(main axis): 아이템이 배치되는 방향.
flex-direction으로 결정된다. - 교차 축(cross axis): 주 축과 수직인 방향.
flex-direction: row(기본값)이면 주 축은 수평(왼쪽→오른쪽), 교차 축은 수직(위→아래)이다. flex-direction: column이면 반대로 주 축이 수직, 교차 축이 수평이 된다.
이게 왜 중요하냐면, justify-content는 주 축 기준, align-items는 교차 축 기준으로 동작하기 때문이다. flex-direction이 바뀌면 이 둘의 동작 방향도 같이 바뀐다.
컨테이너 속성 총정리
flex-direction
아이템을 어느 방향으로 쌓을지 결정한다.
.container {
display: flex;
flex-direction: row; /* 기본값: 가로 방향 */
/* flex-direction: row-reverse; */ /* 가로 역방향 */
/* flex-direction: column; */ /* 세로 방향 */
/* flex-direction: column-reverse; */ /* 세로 역방향 */
}
justify-content
주 축 방향으로 아이템을 어떻게 정렬할지 결정한다. flex-direction: row라면 수평 정렬이다.
.container {
display: flex;
justify-content: flex-start; /* 기본값: 시작점 정렬 */
/* justify-content: flex-end; 끝점 정렬 */
/* justify-content: center; 가운데 정렬 */
/* justify-content: space-between; 양 끝에 붙이고 사이 균등 분배 */
/* justify-content: space-around; 각 아이템 양옆에 균등한 여백 */
/* justify-content: space-evenly; 모든 간격 동일 */
}
실무에서 가장 많이 쓰는 건 flex-start, center, space-between 세 가지다. 내비게이션에서 로고를 왼쪽에, 메뉴를 오른쪽에 붙이는 패턴에 space-between이 딱 맞는다.
align-items
교차 축 방향으로 아이템을 어떻게 정렬할지 결정한다. flex-direction: row라면 수직 정렬이다.
.container {
display: flex;
align-items: stretch; /* 기본값: 컨테이너 높이만큼 늘리기 */
/* align-items: flex-start; 교차 축 시작점 정렬 */
/* align-items: flex-end; 교차 축 끝점 정렬 */
/* align-items: center; 교차 축 가운데 정렬 */
/* align-items: baseline; 텍스트 베이스라인 기준 정렬 */
}
flex-wrap
아이템이 컨테이너 너비를 초과할 때 어떻게 처리할지 결정한다.
.container {
display: flex;
flex-wrap: nowrap; /* 기본값: 줄바꿈 없이 한 줄에 욱여넣기 */
/* flex-wrap: wrap; 아이템이 넘치면 다음 줄로 내리기 */
/* flex-wrap: wrap-reverse; 역방향으로 줄바꿈 */
}
반응형 카드 그리드를 만들 때 flex-wrap: wrap과 flex: 1 1 300px 조합이 자주 쓰인다. 화면 너비에 따라 자동으로 열 수가 조절된다.
gap
아이템 사이의 간격을 지정한다. 예전에는 margin으로 해결했는데, gap이 나오면서 훨씬 깔끔해졌다.
.container {
display: flex;
gap: 16px; /* 행과 열 간격 동일 */
/* gap: 16px 24px; 행 간격 16px, 열 간격 24px */
}
아이템 속성 총정리
flex-grow
컨테이너에 남은 공간이 있을 때 아이템이 얼마나 늘어날지 결정한다. 기본값은 0(늘어나지 않음).
.item {
flex-grow: 0; /* 기본값: 남은 공간 차지 안 함 */
}
.item-main {
flex-grow: 1; /* 남은 공간을 모두 차지 */
}
/* 여러 아이템이 있을 때는 비율로 나눔 */
.sidebar { flex-grow: 1; }
.content { flex-grow: 3; } /* 콘텐츠가 사이드바의 3배 너비 */
flex-shrink
컨테이너 공간이 부족할 때 아이템이 얼마나 줄어들지 결정한다. 기본값은 1(줄어들 수 있음).
.item {
flex-shrink: 1; /* 기본값: 공간 부족 시 줄어듦 */
}
.item-fixed {
flex-shrink: 0; /* 절대 줄어들지 않음 */
}
사이드바처럼 고정 너비를 유지해야 하는 요소에 flex-shrink: 0을 쓰면 좋다.
flex-basis
아이템의 기본 크기를 지정한다. width와 비슷하지만 flex-direction에 따라 너비나 높이가 된다.
.item {
flex-basis: auto; /* 기본값: 콘텐츠 크기 기준 */
/* flex-basis: 200px; */
/* flex-basis: 30%; */
/* flex-basis: 0; flex-grow로만 크기 결정 */
}
flex 단축 속성
flex-grow, flex-shrink, flex-basis를 한 번에 지정한다. 이 방식을 쓰는 게 더 간결하다.
.item {
flex: 0 1 auto; /* 기본값: grow 0, shrink 1, basis auto */
}
.item-flexible {
flex: 1; /* flex: 1 1 0과 동일 — 공간을 균등하게 나눔 */
}
.item-fixed {
flex: 0 0 200px; /* 200px 고정 너비 */
}
align-self
특정 아이템만 교차 축 정렬을 다르게 하고 싶을 때 쓴다. 컨테이너의 align-items를 개별 아이템 레벨에서 오버라이드한다.
.container {
display: flex;
align-items: center; /* 기본적으로 모두 가운데 정렬 */
}
.item-special {
align-self: flex-end; /* 이 아이템만 아래쪽 정렬 */
}
실무에서 자주 쓰는 패턴
완전한 가운데 정렬
예전에는 수직 가운데 정렬이 악명 높았는데, Flexbox로는 두 줄이면 된다.
.container {
display: flex;
justify-content: center; /* 수평 가운데 */
align-items: center; /* 수직 가운데 */
min-height: 100vh; /* 뷰포트 전체 높이 */
}
로딩 스피너, 모달, 히어로 섹션 등에서 항상 쓰는 패턴이다.
내비게이션 바
로고는 왼쪽, 메뉴는 오른쪽, 수직으로는 가운데 정렬.
.navbar {
display: flex;
justify-content: space-between; /* 로고와 메뉴 양 끝 배치 */
align-items: center; /* 수직 가운데 정렬 */
padding: 0 24px;
height: 60px;
}
.nav-menu {
display: flex; /* 메뉴 아이템도 flex로 */
gap: 24px;
list-style: none;
margin: 0;
padding: 0;
}
반응형 카드 그리드
flex-wrap과 flex 단축 속성을 조합하면 미디어 쿼리 없이도 기본적인 반응형 그리드를 만들 수 있다.
.card-grid {
display: flex;
flex-wrap: wrap; /* 넘치면 줄바꿈 */
gap: 16px;
}
.card {
flex: 1 1 280px; /* 최소 280px, 남은 공간 균등 분배 */
/* 화면이 좁아지면 자동으로 한 열로 바뀜 */
}
사이드바 + 메인 콘텐츠 레이아웃
.layout {
display: flex;
gap: 24px;
min-height: 100vh;
}
.sidebar {
flex: 0 0 260px; /* 고정 너비 260px, 줄어들지 않음 */
}
.main-content {
flex: 1; /* 나머지 공간 모두 차지 */
min-width: 0; /* 오버플로우 방지용 */
}
여기서 .main-content에 min-width: 0을 추가하는 이유가 있다. 플렉스 아이템의 기본 min-width는 auto인데, 이러면 콘텐츠가 넘쳐도 아이템이 줄어들지 않는 버그가 생긴다. min-width: 0으로 명시적으로 줄어들 수 있게 해줘야 한다.
버튼 그룹
.button-group {
display: flex;
gap: 8px;
align-items: center;
}
/* 특정 버튼을 오른쪽 끝으로 밀기 */
.button-right {
margin-left: auto; /* 남은 공간을 왼쪽 마진으로 모두 소비 */
}
margin-left: auto는 Flexbox에서 특정 아이템을 반대편 끝으로 밀어내는 트릭이다. justify-content로 전체 배치를 바꾸지 않고도 특정 아이템만 분리할 수 있어서 유용하다.
Flexbox 생성기로 시각적으로 익히기
Flexbox를 글로만 읽으면 한계가 있다. 실제로 속성 값을 바꿔가면서 레이아웃이 어떻게 변하는지 눈으로 확인하는 게 훨씬 빠르다.
toolboxhubs.com/ko/tools/css-flexbox-generator에서 플렉스 컨테이너와 아이템 속성을 실시간으로 조작하고 결과를 바로 확인할 수 있다. 원하는 레이아웃을 만들면 CSS 코드도 자동으로 생성되니, 그대로 프로젝트에 붙여넣기만 하면 된다.
justify-content와 align-items의 조합이 헷갈릴 때 직접 값을 바꿔가며 확인하면 금방 감이 온다.
Flexbox vs CSS Grid
두 가지를 언제 써야 하는지 기준이 명확하지 않아 헷갈리는 경우가 많다.
| 상황 | 추천 |
|---|---|
| 내비게이션 바, 버튼 그룹처럼 단순히 가로로 나열 | Flexbox |
| 카드 목록, 태그 목록처럼 줄바꿈이 자연스럽게 이뤄져야 하는 경우 | Flexbox |
| 복잡한 페이지 레이아웃 (헤더, 사이드바, 메인, 푸터) | Grid |
| 행과 열 위치를 동시에 명시적으로 제어해야 할 때 | Grid |
| 아이템 수가 동적으로 변하는 자동 배치 | Grid |
사실 현대 프론트엔드에서는 둘 중 하나만 쓰는 게 아니라 같이 쓰는 경우가 훨씬 많다. 전체 페이지 구조는 Grid로 잡고, 각 섹션 내부 컴포넌트는 Flexbox로 배치하는 식이다.
흔한 실수 모음
1. flex-direction을 바꿨는데 justify-content가 예상대로 안 된다
flex-direction: column으로 바꾸면 주 축이 수직 방향이 된다. 이때 justify-content는 수직 정렬, align-items는 수평 정렬을 담당한다. row 기준으로 외운 것과 반대가 되니까 헷갈리기 쉽다.
2. 아이템이 컨테이너를 뚫고 나온다
flex-wrap: nowrap(기본값) 상태에서 아이템이 너무 많으면 컨테이너를 초과한다. flex-wrap: wrap으로 바꾸거나, overflow: hidden을 추가하거나, 아이템에 min-width: 0을 설정해보자.
3. flex: 1이 예상대로 작동하지 않는다
flex: 1은 flex: 1 1 0으로 해석된다. flex-basis가 0이 되기 때문에 콘텐츠 크기를 무시하고 남은 공간을 균등하게 나눈다. 콘텐츠 크기를 고려한 균등 분배를 원한다면 flex: 1 1 auto나 그냥 flex-grow: 1을 써야 한다.
4. align-content vs align-items 혼동
align-items는 단일 행에서 아이템의 교차 축 정렬이고, align-content는 flex-wrap으로 여러 줄이 생겼을 때 줄들 사이의 간격과 정렬을 결정한다. 한 줄짜리 컨테이너에서 align-content는 효과가 없다.
5. 이미지를 플렉스 아이템으로 쓸 때 비율이 깨진다
이미지는 기본적으로 align-items: stretch의 영향을 받아 세로로 늘어날 수 있다. 이미지나 이미지를 감싼 컨테이너에 align-self: flex-start 또는 align-items: flex-start를 추가해주면 해결된다.
order 속성으로 시각적 순서 바꾸기
HTML 마크업 순서를 바꾸지 않고 시각적 순서만 변경할 때 order 속성을 쓴다. 기본값은 0이고, 숫자가 작을수록 앞에 배치된다.
/* 모바일에서 이미지를 텍스트 위에 보이게 하기 */
@media (max-width: 768px) {
.content-text { order: 2; }
.content-image { order: 1; }
}
접근성 측면에서는 주의가 필요하다. 스크린 리더는 시각적 순서가 아니라 DOM 순서를 따른다. order로 시각 순서를 바꾸면 시각 사용자와 스크린 리더 사용자가 다른 순서로 콘텐츠를 경험하게 된다.
실전 예제: 댓글 컴포넌트
실제로 자주 마주치는 UI 패턴 하나를 Flexbox로 만들어보자.
/* 아바타 + 내용이 가로로, 내용 안에서 이름과 텍스트가 세로로 쌓이는 댓글 구조 */
.comment {
display: flex;
gap: 12px;
padding: 16px;
}
.comment-avatar {
flex: 0 0 40px; /* 40px 고정, 줄어들지 않음 */
height: 40px;
border-radius: 50%;
overflow: hidden;
}
.comment-body {
flex: 1; /* 남은 공간 모두 차지 */
min-width: 0; /* 긴 텍스트 오버플로우 방지 */
}
.comment-header {
display: flex;
justify-content: space-between; /* 이름 왼쪽, 날짜 오른쪽 */
align-items: baseline; /* 베이스라인 기준 정렬 */
margin-bottom: 4px;
}
.comment-name {
font-weight: 600;
}
.comment-date {
font-size: 0.75rem;
color: #888;
}
이 구조에서 min-width: 0이 없으면 긴 단어나 URL이 컨테이너를 뚫고 나오는 버그가 생긴다. 실무에서 꽤 자주 만나는 문제다.
정리
Flexbox는 CSS 레이아웃의 판도를 바꾼 기술이다. float과 clear로 고통받던 시대를 끝내고, 수직 가운데 정렬을 두 줄로 해결할 수 있게 해줬다.
핵심을 정리하면 이렇다.
- 주 축과 교차 축 개념을 이해하면 나머지는 자연스럽게 따라온다
justify-content는 주 축,align-items는 교차 축flex-direction이 바뀌면 두 속성의 담당 방향도 바뀐다flex: 1로 남은 공간을 균등하게 나눌 수 있다flex-shrink: 0으로 고정 크기를 유지할 수 있다margin: auto는 플렉스 아이템을 반대편으로 밀어내는 트릭이다min-width: 0은 오버플로우 버그의 자주 쓰이는 해결책이다
Flexbox와 Grid는 서로 경쟁 관계가 아니다. 두 가지를 함께 쓰는 게 현대 CSS 레이아웃의 표준 방식이다. 1차원 배치는 Flexbox, 2차원 레이아웃은 Grid라고 기억해두면 선택에서 헷갈리지 않을 것이다.