스타일 · CSS · 레이아웃 · Flex · Grid

CSS · 레이아웃 — Flexbox와 Grid

요소를 어디에·어떻게 배치할지 정하는 것이 레이아웃입니다. CSS? 에는 한 줄로 나란히 세우는 Flexbox, 바둑판처럼 칸을 짜는 Grid, 그리고 요소를 띄워 겹치는 position 이 있습니다.

Flexbox는 옷걸이 봉 하나에 옷을 죽 거는 것(한 줄 정렬), Grid는 약장 서랍처럼 가로·세로 칸을 미리 짜 두고 물건을 넣는 것이라고 보면 쉽습니다.

레이아웃 CSS가 있고 없고의 차이를 먼저 눈으로 보세요. 똑같은 박스 세 개인데, 왼쪽은 그냥 세로로 쌓이고(기본), 오른쪽은 display:flex 한 줄로 가로 정렬됩니다.

이 페이지 사용법

개념마다 직접 고쳐 실행할 수 있는 라이브 데모가 있습니다. 안의 코드를 바꾸고 실행을 눌러 보세요. 값을 직접 만져 봐야 레이아웃이 손에 익습니다.

1. 일반 흐름(normal flow)

아무 배치 속성도 안 주면 블록 요소(div 등)는 위에서 아래로 한 줄씩 쌓이고, 인라인 요소(span 등)는 왼쪽에서 오른쪽으로 흐릅니다 — 이 기본 동작을 일반 흐름이라 부릅니다.

2. Flexbox — 한 줄(또는 한 열) 정렬의 왕

무엇: 부모에 display:flex 를 주면 그 부모는 플렉스 컨테이너가 되고, 직계 자식들은 플렉스 아이템이 되어 한 축(가로 또는 세로)을 따라 늘어섭니다. 정렬·간격·줄바꿈을 속성 몇 개로 끝낼 수 있습니다.

방향 — flex-direction

무엇: 아이템이 늘어서는 축(주축, main axis)을 정한다. row(기본·가로), column(세로), 그리고 역방향 row-reverse / column-reverse.

.wrap {
  display: flex;
  flex-direction: row;   /* 가로 한 줄 (기본값) */
}

아래에서 flex-directioncolumn 으로 바꿔 세로로 세워 보세요.

주축 정렬 — justify-content

무엇: 주축(가로 기본) 방향으로 아이템들을 어떻게 분배할지. 자주 쓰는 값:

flex-start시작 쪽으로 몰기 (기본)
center가운데로 모으기
flex-end끝 쪽으로 몰기
space-between양 끝에 딱 붙이고 사이를 균등하게
space-around각 아이템 양옆에 같은 여백
space-evenly모든 틈(끝 포함)을 완전히 동일하게

justify-content 값을 위 표의 다른 값으로 바꿔 보세요.

교차축 정렬 — align-items

무엇: 주축과 직각인 축(교차축, cross axis)으로 정렬. row 일 때는 세로 정렬을 뜻한다. 값: stretch(기본·꽉 채움), flex-start, center, flex-end, baseline(글자 밑선 맞춤).

컨테이너 높이가 큰 상황에서 align-itemscenter/flex-end 로 바꿔 보세요.

완전 가운데 정렬 — 가장 유명한 비법

무엇: justify-content:center (가로 가운데) + align-items:center (세로 가운데) 를 함께 주면 자식이 정확히 한가운데에 옵니다. 예전엔 어렵던 일이 두 줄로 끝납니다.

간격 — gap

무엇: 아이템 사이의 을 한 번에 준다. 예전엔 margin 으로 일일이 줬지만 이제 gap 한 줄이면 됩니다. gap: 세로 가로 로 두 값도 가능.

.wrap {
  display: flex;
  gap: 12px;          /* 모든 아이템 사이 12px */
  /* gap: 8px 20px;   세로 8px, 가로 20px */
}

줄바꿈 — flex-wrap

무엇: 기본값 nowrap 은 한 줄에 욱여넣어 아이템을 찌그러뜨린다. wrap 을 주면 공간이 부족할 때 다음 줄로 넘김. 카드 목록에 필수.

아래 데모에서 flex-wrapnowrap 으로 바꾸면 카드가 한 줄에 눌려 들어가는 걸 볼 수 있어요.

아이템 속성 — flex / order / align-self

무엇: 컨테이너가 아니라 아이템 각각에 주는 속성들.

  • flex: 1 — 남는 공간을 나눠 차지. 여러 아이템에 flex:1 을 주면 똑같이 늘어남. (flex-grow flex-shrink flex-basis 의 단축)
  • flex-grow — 남는 공간을 차지하는 비율(기본 0=안 늘어남). 21 짜리의 두 배로 늘어남.
  • flex-shrink — 공간이 모자랄 때 줄어드는 비율(기본 1). 0 이면 안 줄어듦.
  • flex-basis — 늘이고 줄이기 전의 기본 크기(예: 200px, 기본 auto).
  • order — 화면에 그려지는 순서(기본 0). 작을수록 앞. HTML 순서를 바꾸지 않고 보이는 순서만 조정.
  • align-self — 그 아이템만 교차축 정렬을 따로(컨테이너의 align-items 무시).

가운데 박스에만 flex:1 을 줘서 남는 공간을 다 먹게 했습니다. 숫자를 flex:2 로 바꿔 보세요.

orderalign-self 도 한 번에 — "3"이 order:-1 로 맨 앞에 오고, 자기만 위로 붙습니다.

3. Grid — 가로·세로 칸을 짜는 2차원 레이아웃

무엇: 부모에 display:grid 를 주면 그리드 컨테이너가 된다. Flexbox가 한 줄(1차원)에 강하다면, Grid는 행과 열(2차원)을 동시에 짜는 데 강하다. 칸 구조를 미리 정의하고 그 안에 아이템을 배치한다.

열 정의 — grid-template-columns

무엇: 몇 칸을 어떤 너비로 만들지. 단위가 핵심:

  • 200px — 고정 너비
  • 1fr남는 공간의 비율(fraction). 1fr 1fr 은 반반, 2fr 1fr 은 2:1
  • repeat(3, 1fr)1fr 1fr 1fr 의 줄임. "3칸 균등"을 짧게
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);  /* 균등 3칸 */
  gap: 12px;                               /* 칸 사이 간격 */
}

repeat(3, 1fr) 의 숫자를 4 로 바꾸면 4칸이 됩니다. 2fr 1fr 1fr 처럼 비율도 섞어 보세요.

행 정의와 자동 채움 — grid-template-rows · auto-fit

무엇: grid-template-rows 는 행 높이를 정한다. 칸 개수를 화면 너비에 맞게 자동 조절하려면 repeat(auto-fit, minmax(150px, 1fr)) 패턴을 쓴다 — "최소 150px, 들어갈 수 있는 만큼 칸을 만들어라". 갤러리에 안성맞춤.

아래는 자동으로 칸 수가 늘고 줄어드는 카드 갤러리. 크게 보기 로 넓혀 칸이 늘어나는 걸 확인해 보세요.

칸 합치기 — grid-column / grid-row span

무엇: 아이템 하나가 여러 칸을 차지하게 한다. grid-column: span 2 는 "가로로 2칸", grid-row: span 2 는 "세로로 2칸". grid-column: 1 / 3 처럼 몇 번째 선부터 몇 번째 선까지로도 지정할 수 있다(칸이 아니라 칸 사이의 번호).

첫 칸은 가로 2칸, 둘째 칸은 세로 2칸을 차지하게 했습니다. span 숫자를 바꿔 보세요.

이름표로 배치 — grid-template-areas

무엇: 칸마다 이름을 붙여 그림 그리듯 레이아웃을 짠다. 컨테이너에서 grid-template-areas 로 지도를 그리고, 각 아이템에 grid-area: 이름 을 주면 그 자리에 들어간다. 같은 이름을 여러 칸에 쓰면 그만큼 영역이 합쳐진다. 점(.)은 빈 칸.

아래는 헤더 · 사이드바 · 본문 구조. 따옴표 안의 지도를 바꿔 배치를 재구성해 보세요.

4. position — 흐름에서 떼어내 자유 배치

무엇: 요소를 일반 흐름에서 띄워 원하는 곳에 둔다. top · right · bottom · left 로 위치를, z-index 로 겹침 순서를 조정한다. 다섯 가지 값을 알아 두면 충분하다.

기준
static기본. 일반 흐름 그대로(top/left 무시)
relative원래 자리에서 살짝 이동. 자리는 그대로 차지자기 원래 위치
absolute흐름에서 빠져 자유 배치가장 가까운 relative(등) 조상
fixed화면(뷰포트)에 고정. 스크롤해도 안 움직임뷰포트
sticky평소엔 흐름대로, 스크롤하다 정해진 위치에서 달라붙음스크롤 컨테이너
absolute의 핵심 짝꿍

position:absolute 자식은 가장 가까운 position이 static이 아닌 조상을 기준으로 배치됩니다. 그래서 보통 부모에 position:relative 를 먼저 주고, 자식에 absolute 를 줍니다. 이걸 안 하면 화면 전체를 기준으로 튀어 버립니다.

카드 모서리에 배지를 absolute 로 붙인 예. 부모가 relative 라 카드 기준으로 배치됩니다. top/right 값을 바꿔 보세요.

position:sticky 헤더 — 안쪽 영역을 스크롤하면 "고정 헤더"가 위에 달라붙습니다. top:0 이 달라붙는 위치입니다.

z-index 는 겹친 요소의 앞뒤 순서를 정합니다. 숫자가 클수록 위로 올라옵니다. position 이 static이 아닌 요소에서만 작동합니다.

5. float · clear — 옛 방식 (참고만)

무엇: 원래 float 은 이미지 옆에 글자를 흐르게 하려고 만든 속성인데, 과거엔 이걸로 전체 레이아웃까지 짰습니다. clear 는 float을 해제하는 짝입니다. 지금은 레이아웃에 거의 쓰지 않습니다flexgrid 가 훨씬 쉽고 정확합니다.

img { float: left; }      /* 이미지를 왼쪽에, 글자는 그 오른쪽으로 흐름 */
.footer { clear: both; }  /* 위의 float 영향에서 벗어남 */
레이아웃에는 쓰지 마세요

float 로 짠 레이아웃은 높이 붕괴(clearfix 필요) 등 골치 아픈 문제가 많습니다. 글을 이미지 주위로 감싸는 본래 용도 외에는 flex/grid 를 쓰세요.

6. 실전 — 헤더·사이드바·본문 레이아웃

실무에서 가장 흔한 화면 구조(상단 헤더 + 좌측 사이드바 + 우측 본문)를 Grid로 짜면 단 몇 줄입니다. grid-template-areas 로 지도를 그리는 방식이 읽기 쉽습니다.

사이드바(nav)를 본문과 푸터 두 행에 걸쳐 같은 이름으로 적었기 때문에 세로로 길게 이어집니다. 지도 문자열만 바꾸면 구조가 통째로 바뀝니다.

한눈에 — Flex/Grid 속성 카탈로그

대상속성역할
Flex 컨테이너display:flex플렉스 켜기
Flex 컨테이너flex-direction주축 방향 (row/column)
Flex 컨테이너justify-content주축 정렬·분배
Flex 컨테이너align-items교차축 정렬
Flex 컨테이너flex-wrap줄바꿈 허용
Flex/Grid 공통gap아이템 사이 간격
Flex 아이템flexgrow·shrink·basis 단축
Flex 아이템order보이는 순서
Flex 아이템align-self자기만 교차축 정렬
Grid 컨테이너display:grid그리드 켜기
Grid 컨테이너grid-template-columns열 정의 (fr·px·repeat)
Grid 컨테이너grid-template-rows행 정의
Grid 컨테이너grid-template-areas이름표로 영역 배치
Grid 아이템grid-column / grid-row칸 합치기 (span·선번호)
Grid 아이템grid-area영역 이름 지정
위치positionstatic/relative/absolute/fixed/sticky
위치top·right·bottom·left좌표 이동
위치z-index겹침 순서
실무 메모 — 언제 flex, 언제 grid?

Flex는 한 방향(1차원). 메뉴 한 줄, 버튼 묶음, 카드 안의 가로 정렬처럼 "한 줄로 늘어놓고 정렬"이 핵심일 때.

Grid는 두 방향(2차원). 페이지 전체 골격(헤더·사이드바·본문), 카드 갤러리, 표 같은 격자처럼 "행과 열을 동시에" 짜야 할 때.

둘은 섞어 씁니다: 페이지 큰 틀은 Grid로, 그 안 헤더의 로고·메뉴 정렬은 Flex로 — 가 흔한 조합입니다.

다음 단계

레이아웃으로 배치를 끝냈다면, 다음은 글자·색·배경을 다듬을 차례입니다. 타이포 · 색 · 배경 으로 이어집니다.