본문 바로가기
StyleSheet/CSS

[CSS] Flexbox: 1차원 레이아웃의 모든 것

반응형

과거 웹 개발자들은 화면에 박스 3개를 나란히 가로로 배치하기 위해 피눈물을 흘렸습니다. float: left를 썼다가 부모의 높이가 찌그러지는 버그(Height Collapse)를 막기 위해 clearfix라는 흑마법 코드를 덧붙여야 했고, 수직 중앙 정렬(Vertical Center)을 맞추기 위해 line-heightmargin 값을 픽셀 단위로 찍어 맞추는 노가다를 반복했습니다. 브라우저 창 크기가 변하는 스마트폰 시대가 도래하자, 이 구시대적 해킹 레이아웃은 여지없이 와르르 무너져 내렸습니다.

전 세계 개발자들의 절규를 들은 W3C는 마침내 2009년 초안을 거쳐, 오로지 '레이아웃 배치'만을 목적으로 창조된 완벽하고 우아한 구세주를 세상에 내놓았습니다. 그것이 바로 CSS Flexible Box Layout Module, 줄여서 'Flexbox'입니다. Flexbox의 등장 이후, 수백 줄의 float와 픽셀 노가다 코드가 단 세 줄의 코드로 압축되는 마법이 일어났습니다. 오늘날 모든 프론트엔드 UI(네비게이션 바, 카드 리스트, 모달창 등)의 99%는 이 Flexbox를 기반으로 만들어집니다.

이번 글에서는 Flexbox의 핵심 철학인 Main Axis(주축)와 Cross Axis(교차축)의 개념을 뇌에 각인시키고, 부모(Container)에게 내리는 정렬의 마법 주문들에 대해 상세히 알아보겠습니다.

1. 패러다임의 전환: 부모(Container)와 자식(Item)의 분업

Flexbox 레이아웃을 다루기 전에 반드시 명심해야 할 절대 규칙이 있습니다. Flexbox는 '부모 박스(Flex Container)'에게 내리는 명령'자식 박스(Flex Item)'에게 내리는 명령이 완전히 분리되어 있다는 점입니다. display: flex;라는 마법의 주문을 '부모 요소'에게 외우는 순간, 그 뱃속에 있는 직계 자식들은 기존의 멍청한 Block 성질을 잃어버리고 가로세로로 유연하게 늘어나는 고무줄(Flex Item)로 변신하게 됩니다.

이번 1편에서는 자식들의 배치 방향과 정렬 기준을 통제하는 '부모(Container) 전용 속성'들에 집중하겠습니다.

2. 레이아웃의 기준선: Main Axis(주축)와 Cross Axis(교차축)

수많은 초보 개발자들이 justify-content는 가로 정렬, align-items는 세로 정렬이라고 단순히 암기합니다. 그리고 나중에 축이 뒤틀렸을 때 멘탈이 붕괴됩니다. Flexbox는 가로/세로라는 고정된 개념이 없습니다. 오직 '주축(중심축)(Main Axis)''교차축(Cross Axis)'이라는 두 개의 가상 선만 존재할 뿐입니다.

축의 방향을 결정하는 자: flex-direction

부모 요소에 display: flex;를 주면, 기본적으로 flex-direction: row;가 생략되어 들어갑니다. 즉, 메인 주축이 왼쪽에서 오른쪽(가로)으로 형성됩니다. 이때 교차축은 위에서 아래(세로)가 됩니다.

하지만 flex-direction: column;으로 변경하는 순간 마법이 일어납니다. 메인 주축이 위에서 아래(세로)로 90도 꺾여버립니다! 자연히 교차축은 가로가 됩니다. 이 '주축의 방향'을 완벽히 이해해야만 아래에 나오는 정렬 속성들을 헷갈리지 않고 자유자재로 다룰 수 있습니다.

3. 메인 축(Main Axis)을 따라 정렬하라: justify-content

justify-content는 현재 메인 주축을 따라 자식 박스들을 어떻게 흩어놓을 것인가를 결정합니다. (기본 row 상태에서는 가로 정렬을 의미합니다.)

  • flex-start (기본값): 아이템들을 주축의 시작점(왼쪽)으로 전부 다닥다닥 밀어붙입니다.
  • flex-end: 아이템들을 주축의 끝점(오른쪽)으로 싹 다 밀어냅니다. (로그인, 회원가입 버튼을 우측 끝으로 몰아넣을 때 꿀팁!)
  • center: 주축의 한가운데로 아이템들을 모읍니다. (가로 중앙 정렬의 구세주)
  • space-between: 첫 번째 아이템은 맨 왼쪽, 마지막 아이템은 맨 오른쪽에 찰싹 붙이고, 나머지 중간 아이템들은 남은 여백을 아주 공평하게 똑같이 나누어 가집니다. [실무 99% 사용] 네비게이션 로고와 메뉴바를 양끝으로 쫙 찢어놓을 때 씁니다.
  • space-around: 모든 아이템들의 좌우 양옆에 동일한 크기의 '개인 영역(여백)'을 둥글게 둘러쳐줍니다.

4. 교차 축(Cross Axis)을 따라 정렬하라: align-items

align-items는 메인 주축과 90도로 직교하는 교차축을 따라 자식 박스들을 어떻게 오와 열을 맞출 것인가를 결정합니다. (기본 row 상태에서는 세로 정렬을 의미합니다.)

  • stretch (기본값): 자식 요소에 높이(height) 값이 지정되어 있지 않다면, 부모의 높이만큼 위아래로 쭉쭉 늘어나서 꽉 채웁니다. 옛날에는 옆에 있는 박스 높이에 맞춰 내 박스 높이도 똑같이 늘리는 게 지옥이었지만, flex는 기본값이 stretch라 아무것도 안 해도 높이가 완벽히 똑같아집니다!
  • center: 높이가 제각각인 텍스트와 이미지, 아이콘들을 세로 정중앙에 하나의 꼬치로 완벽하게 꿰어버립니다. margin-top 노가다를 역사의 뒤안길로 보내버린 프론트엔드 최고의 혁명 코드입니다.
  • flex-start / flex-end: 아이템들을 교차축의 시작점(위)이나 끝점(아래)으로 정렬합니다.

💡 전설의 궁극기: 완벽한 정중앙 정렬

과거 웹 개발 면접의 단골 질문이었던 "화면 한가운데에 박스를 어떻게 띄우나요?"에 대한 현대 프론트엔드의 모범 답안은 단 3줄이면 끝납니다.

.container {
    display: flex;
    justify-content: center; /* 가로(주축) 중앙 정렬 */
    align-items: center;     /* 세로(교차축) 중앙 정렬 */
    height: 100vh;           /* 화면 전체 높이 확보 */
}

5. 줄 바꿈의 미학: flex-wrap

부모 박스는 좁은데 자식 박스가 10개나 들어온다면 어떻게 될까요? 기본적으로 Flexbox는 무자비합니다. 자식들이 찌그러지는 한이 있더라도 무조건 한 줄(nowrap)에 다 쑤셔 넣습니다. 하지만 쇼핑몰의 상품 리스트처럼 공간이 부족하면 자연스럽게 아래 줄로 떨어지게 만들고 싶다면 flex-wrap: wrap; 속성을 주면 됩니다. 이 속성 하나로 스마트폰(1줄), 태블릿(2줄), PC(4줄)로 자연스럽게 흐르는 반응형 갤러리 레이아웃이 완성됩니다.

정리하며

이번 글에서는 구시대의 찌꺼기 float를 완벽하게 대체하고 레이아웃의 패러다임을 바꾼 Flexbox의 '부모(Container) 통제술'을 깊이 있게 살펴보았습니다. 주축(Main Axis)과 교차축(Cross Axis)의 흐름을 이해하고 justify-contentalign-items로 여백과 오와 열을 맞추는 법을 터득했다면, 당신은 이미 1차원 배치 레이아웃의 90%를 정복한 것입니다. 그런데, 정렬은 부모가 시키는 대로 다 했는데, "나는 옆에 있는 애들보다 두 배로 더 크게 늘어나고 싶어!", "나는 공간이 부족해도 절대 쪼그라들기 싫어!"라고 떼를 쓰는 개성 넘치는 자식(Item) 요소들이 있다면 어떻게 통제해야 할까요? 다음이번 포스팅에서는 고무줄처럼 늘어나고 줄어드는 "CSS Flexbox (2편): 자식(Item)의 반란, flex-grow와 shrink의 황금 비율"에 대해 상세히 파헤쳐 보겠습니다!


CSS Flexbox 컨테이너 속성 - 1차원 레이아웃의 구원자

Float와 Position으로 고통받던 프론트엔드 개발자들에게 한 줄기 빛처럼 강림한 기술, 바로 Flexbox(Flexible Box Layout)입니다. Flexbox는 그 이름처럼 상자들의 크기를 뷰포트나 내용물에 맞게 아주 '유연하게' 늘이거나 줄이며 배치할 수 있도록 설계된 현대적인 1차원(가로 혹은 세로) 레이아웃 모델입니다. display: flex; 단 한 줄을 선언하는 순간, 부모 요소는 전지전능한 지휘자(Container)가 되어 자식 요소들(Items)의 방향, 정렬, 간격을 마음대로 주무를 수 있게 됩니다. 가운데 정렬을 하기 위해 margin: auto를 주며 씨름하던 과거는 잊으십시오.

1. 선언과 동시에 시작되는 마법: display: flex

정렬하고 싶은 요소들을 감싸는 부모 태그에 display: flex;를 선언하는 순간, 그 부모는 Flex Container가 되고 직계 자식들은 자동으로 Flex Item으로 변신합니다.

.container {
    display: flex; /* 마법의 시작 */
}

이 한 줄만으로도 자식 요소들은 마치 inline-block을 준 것처럼 가로로 사이좋게 일렬로 늘어서게 됩니다. 블록 요소의 붕괴를 막기 위해 Clearfix를 쓰던 Float의 고통이 순식간에 사라지는 순간입니다.

2. 뼈대를 세우는 방향 설정: flex-direction

아이템들을 어느 방향으로 나열할지 결정합니다. 이것이 Flexbox의 **'주축(Main Axis)'**을 결정하는 가장 중요한 속성입니다.

  • row (기본값): 왼쪽에서 오른쪽으로 (가로 배치)
  • row-reverse: 오른쪽에서 왼쪽으로 역순 배치 (우측 정렬 시 유용)
  • column: 위에서 아래로 (세로 배치 - 모바일 레이아웃의 핵심)
  • column-reverse: 아래에서 위로 역순 배치

3. 주축(Main Axis) 정렬의 마술사: justify-content

flex-direction으로 결정된 주축 방향을 따라 아이템들 사이의 '여백'을 어떻게 배분할지 결정합니다.

  • flex-start (기본값): 시작점으로 옹기종기 모음
  • center: 가운데로 예쁘게 모음
  • space-between: [실무 1순위] 첫 아이템은 끝에, 마지막 아이템도 끝에 딱 붙이고, 나머지 여백은 중간에 균등하게 배분. (네비게이션 바 양끝 정렬에 필수!)
  • space-around: 아이템들의 둘레에 동일한 여백을 둘러줌.

4. 교차축(Cross Axis) 정렬: align-items

주축의 수직 방향(교차축)으로 아이템들을 어떻게 정렬할지 결정합니다. 보통 요소들의 수직 중앙 정렬을 맞출 때 사용합니다.

  • stretch (기본값): 아이템들이 십자가 방향으로 쭉 늘어나서 컨테이너의 높이를 꽉 채웁니다.
  • center: [실무 1순위] 아이템들을 수직 중앙에 예쁘게 배치합니다.
  • flex-start / flex-end: 위쪽이나 아래쪽으로 모읍니다.

💡 영원한 난제 해결: 완벽한 정중앙 배치 공식

과거 marginposition을 조합해 픽셀을 쪼개가며 맞추던 정중앙 배치가 Flexbox로는 단 3줄이면 끝납니다. 프론트엔드 개발자라면 자다가도 외워야 하는 필수 공식입니다.

.perfect-center {
    display: flex;
    justify-content: center; /* 가로 중앙 정렬 */
    align-items: center;     /* 세로 중앙 정렬 */
    height: 100vh;           /* 화면 꽉 찬 높이 기준 */
}

5. 줄바꿈의 지배자: flex-wrap

Flexbox의 기본 성질은 아이템들이 아무리 많아도 절대 줄바꿈을 하지 않고 자신의 크기를 찌그러뜨리면서라도 한 줄에 우겨넣으려 한다는 것입니다(nowrap). 아이템의 크기를 유지하면서 넘치면 다음 줄로 떨어지게 하려면 wrap 속성을 반드시 줘야 합니다.

.gallery-container {
    display: flex;
    flex-wrap: wrap; /* 자리가 모자라면 아래로 예쁘게 떨어져라! */
    gap: 20px;       /* 아이템들 사이의 여백 (최신 속성) */
}

정리하며

부모 요소(Container)에 display: flex를 선언하고, flex-direction으로 뼈대를 잡은 뒤, justify-contentalign-items로 중앙 정렬을 맞추는 이 패턴은 현대 웹 개발의 레이아웃을 구성하는 가장 기초적이고 완벽한 설계도입니다. 지휘자가 무대를 세팅했다면, 이제 무대 위에서 연주하는 개별 악기(Item)들을 세밀하게 튜닝할 차례입니다. 다음이번 포스팅에서는 화면 크기에 맞춰 아이템들이 고무줄처럼 늘어나고 줄어드는 마법, "Flexbox 아이템 속성 (팽창, 축소, 유연한 크기)"에 대해 뼈 때리게 파헤쳐 보겠습니다!


CSS Flexbox (2편: Item) - 고무줄처럼 늘어나고 줄어드는 자식들의 영역 다툼 (Grow, Shrink)

우리가 직전이번 포스팅에 서 다루었던 것은 오직 '부모(Flex Container)'의 입장이었습니다. 부모가 display: flex를 선언하고, 자식들을 왼쪽으로 밀어붙일지(justify-content), 세로로 중앙에 줄을 세울지(align-items)라는 전체적인 '정렬과 방향'의 규칙을 통제하는 법을 배웠습니다. 하지만 실무 레이아웃은 그렇게 호락호락하지 않습니다. "왼쪽의 메뉴바는 무조건 250px로 크기를 고정하고, 오른쪽 본문 영역은 사용자의 모니터가 커지면 커지는 대로 남은 빈 공간을 쫙쫙 다 빨아들여서 넓어지게 해주세요!" 같은 디테일하고 이기적인 요구사항들이 쏟아집니다. 이때 필요한 것이 바로 '자식(Flex Item) 요소'들에게 개별적으로 부여하는 고무줄 속성들입니다. Flexbox의 진짜 강력함은 부모의 정렬 명령에 얌전히 따르는 것을 넘어, 자식들끼리 남은 잉여 공간을 두고 치열하게 '비율 싸움'을 벌이거나, 좁은 공간에서 누가 덜 찌그러질지 눈치 게임을 하는 동적인(Flexible) 크기 조절에 있습니다. 이번 글에서는 주니어 개발자들이 가장 헷갈려 하지만 반응형 UI의 절대 코어 기술인 flex-grow, flex-shrink, flex-basis의 수학적 팽창/수축 원리와, HTML 뼈대를 뜯어고치지 않고도 화면 순서를 마술처럼 바꿔치기하는 order 속성까지 상세히 알아보겠습니다.

1. 공간을 향한 탐욕: flex-grow (팽창 지수)

자식 박스들은 태어날 때 기본적으로 flex-grow: 0;이라는 속성을 가집니다. 즉, 부모 박스가 아무리 넓어서 옆에 빈 텅 빈 공간(여백)이 태평양처럼 남아돌아도, 자식들은 딱 자신의 알맹이(콘텐츠) 크기나 지정된 width 만큼만 공간을 차지하고 더 이상 욕심을 내지 않습니다.

하지만 특정 자식에게 flex-grow: 1;이라는 탐욕의 마법을 부여하는 순간 돌변합니다. 이 자식 요소는 부모 박스 내부에 남은 '잉여 공간'을 남김없이 쫙 빨아들여서 자기 덩치를 늘려버립니다. 만약 두 명의 자식에게 모두 flex-grow: 1;을 주면 어떻게 될까요? 남은 빈 공간을 정확히 1:1 비율로 공평하게 나누어 먹고 사이좋게 늘어납니다. 만약 첫 번째 자식에게 grow: 2를, 두 번째 자식에게 grow: 1을 준다면? 남은 공간을 2:1의 비율로 파이 나누듯이 쪼개 가져갑니다. 이 속성을 이용하면 모니터가 커지든 작아지든 화면을 꽉 채우는 '스프링 같은' 반응형 그리드를 수학적 계산(px) 없이 완벽하게 구현해 냅니다.

2. 생존을 위한 다이어트: flex-shrink (수축 지수)

반대로, 부모 박스가 좁아져서 자식들이 살 공간이 부족해지면(Overflow 위기) 어떻게 될까요? 자식들의 기본값은 flex-shrink: 1;입니다. 즉, "공간이 부족하면 우리 모두 사이좋게 똑같은 비율로 자신의 덩치를 깎아서(수축해서) 이 비좁은 부모 박스 안에 어떻게든 다 같이 우겨 들어가자!"라는 훌륭한 희생정신을 가지고 있습니다.

하지만 실무에서는 "왼쪽에 있는 프로필 사진 박스는 화면이 좁아져도 절대 찌그러지면 안 돼!"라는 요구가 생깁니다. 이때 프로필 사진 박스에 flex-shrink: 0; (수축을 거부함)을 주면, 이 박스는 강철처럼 단단해져서 공간이 아무리 좁아져도 자기 본래 크기를 절대 포기하지 않습니다. 대신 그 옆에 있는 가엾은 텍스트 박스들이 남은 몫까지 덤터기를 쓰고 엄청나게 쪼그라들며 화면을 방어하게 됩니다. 이것이 모바일 반응형 UI에서 특정 고정 크기 UI를 보호하는 핵심 스킬입니다.

3. 팽창과 수축의 출발선: flex-basis (기본 크기)

width 속성과 아주 비슷해 보이지만, Flexbox 생태계에서는 훨씬 강력하고 똑똑한 녀석입니다. flex-basis는 자식 박스들이 grow(팽창)나 shrink(수축)를 시작하기 전, "공간을 나누기 전 나의 쌩얼(최초) 크기는 이거야!"라고 브라우저에게 선언하는 기준점(Base)입니다.

기본값은 auto이며, 이는 자식 박스 안에 들어있는 글씨나 콘텐츠의 고유 크기를 출발선으로 삼겠다는 뜻입니다. 만약 flex-basis: 200px;을 주면, 일단 200px의 크기를 먹고 들어간 상태에서, 남은 공간을 grow 비율에 따라 더 가져오거나, 좁으면 shrink 비율에 따라 200px에서 살을 깎아내기 시작합니다. Flex 레이아웃 내부에서는 멍청한 width 속성을 지워버리고 유연한 flex-basis를 사용하는 것이 렌더링 버그를 막는 프론트엔드의 정석입니다.

4. 실무 최강의 압축 마법: flex 단축 속성 (Shorthand)

고수들은 위 세 가지 속성을 세 줄에 걸쳐 쓰지 않고, flex라는 단축 속성 하나로 우아하게 뭉뚱그려 사용합니다.

/* 💡 실무 Flex Item 삼위일체 공식 */
.item {
    /* flex: [grow] [shrink] [basis] */
    flex: 1 1 auto; 
    /* 해석: 공간이 남으면 1의 비율로 팽창하고, 모자라면 1의 비율로 수축하며, 최초 크기는 콘텐츠 알맹이 기준(auto)으로 해라! */
}

.fixed-sidebar {
    flex: 0 0 250px;
    /* 해석: 남는 공간을 먹지도 않고(0), 좁아져도 수축하지 않으며(0), 영원히 250px이라는 강철 같은 고정 크기를 유지하라! */
}

5. 마이웨이를 걷는 녀석들: align-self와 order

부모(Container)가 align-items: center;로 모든 자식들을 세로 정중앙에 집합시켰습니다. 그런데 막내 자식 하나만 "난 싫어! 난 위쪽에 붙을 거야!"라고 반항하고 싶을 때, 부모의 전체 명령을 개무시하고 혼자서만 튀는 정렬을 가능케 하는 속성이 바로 align-self: flex-start;입니다.

더욱 충격적인 것은 order 속성입니다. HTML 코드상으로는 1번, 2번, 3번 순서로 태그가 짜여 있더라도, 1번 요소에 order: 3;을, 3번 요소에 order: 1;을 줘버리면 브라우저 화면에는 3번이 제일 먼저 나오고 1번이 맨 끝으로 밀려나는 시각적 재배치 마술이 일어납니다. 자바스크립트로 DOM 구조를 뜯어고칠 필요 없이, 오직 CSS만으로 모바일 화면에서 특정 중요한 광고 박스나 메뉴를 맨 위로 끌어올리는 반응형 UX의 강력한 무기로 쓰입니다. 단, 시각적으로만 순서가 바뀌고 실제 시각 장애인용 스크린 리더기가 읽는 순서(HTML 구조)는 변하지 않으므로 접근성 측면에서는 남발해서는 안 됩니다.

정리하며

이번 글에서는 부모의 통제 속에 놓인 자식들(Item)이 어떻게 서로 공간을 두고 밀당(Grow, Shrink)을 하며, 자신만의 고유한 비율(Basis)을 방어해 내는지에 대한 Flexbox의 심화 수학 모델을 상세 분석 해보았습니다. 1편의 Container 속성과 2편의 Item 속성을 완벽히 버무릴 줄 안다면, 지구상에 존재하는 그 어떤 1차원 배치의 UI(네비게이션, 푸터, 댓글 리스트)도 완벽하게 반응형으로 찍어낼 수 있습니다. 하지만, 인간의 욕망은 끝이 없습니다. "가로 한 줄 맞추는 건 알겠어. 그런데 바둑판처럼 가로세로를 동시에 완벽하게 바둑판 썰 듯이 나누고 그 칸 안에 요소들을 자유자재로 꽂아 넣을 순 없을까?" 1차원(선)의 한계를 부수고 2차원(면)의 세계로 진입하는 CSS 레이아웃의 끝판왕이자 최종병기! 다음이번 포스팅에서는 "CSS Grid (1편): Flexbox의 한계를 부수는 2차원 바둑판 레이아웃의 탄생"에 대해 상세히 파헤쳐 보겠습니다!


CSS Flexbox 아이템 속성 - 팽창, 축소, 유연한 크기의 마법

이전 포스팅에서 우리는 Flexbox의 부모(Container) 요소가 지휘자가 되어 전체적인 정렬과 방향을 통제하는 방법을 배웠습니다. 하지만 진정한 '유연함(Flexibility)'의 기적은 자식 요소들(Flex Items) 각각에 부여되는 세밀한 조율 속성에서 완성됩니다. 뷰포트(브라우저 창)가 넓어지면 남는 공간을 누가 얼마나 더 차지할 것인가? 반대로 창이 좁아지면 누가 양보해서 찌그러질 것인가? 이를 결정하는 속성인 flex-grow, flex-shrink, flex-basis 삼총사를 완벽히 이해해야만 진정한 반응형 UI를 구축할 수 있습니다.

1. 팽창의 욕망: flex-grow

부모 컨테이너 안에 아이템들을 나열하고 났더니, 오른쪽에 휑하게 빈 공간(여백)이 남는 경우가 있습니다. 이때 아이템에게 flex-grow 속성을 주면, 아이템이 마치 스펀지처럼 부풀어 올라 남는 빈 공간을 싹싹 긁어먹습니다. 기본값은 0(늘어나지 않음)입니다.

비율로 공간을 찢어라!

만약 아이템 A에는 flex-grow: 1;을, 아이템 B에는 flex-grow: 2;를 준다면 어떻게 될까요? 부모의 빈 공간을 3등분(1+2)하여 A가 1만큼, B가 2만큼 더 커지게 됩니다. 실무에서는 보통 특정 입력창(Input)이 남는 공간을 모두 차지하게 만들 때 사용합니다.

.search-bar { display: flex; }
.search-input {
    /* 💡 버튼이 차지하고 남은 나머지 전체 가로 공간을 내가 전부 독식하겠다! */
    flex-grow: 1; 
}
.search-button {
    flex-grow: 0; /* 나는 원래 크기만 유지할게 */
    width: 50px;
}

2. 양보와 희생의 미덕: flex-shrink

화면이 좁아져서 아이템들이 부모 컨테이너를 뚫고 튀어나가려고 할 때 작동하는 방어 기제입니다. 기본값은 1이며, 이는 "공간이 부족하면 내 몸을 찌그러뜨려서라도 부모 박스 안에 머물겠다"는 뜻입니다.

숫자가 클수록 더 많이 찌그러집니다. 만약 특정 요소(예: 로고나 프로필 이미지)가 절대 찌그러지지 않고 원형을 보존하게 만들고 싶다면 flex-shrink: 0;을 주면 됩니다. (실무 레이아웃 붕괴 방지의 핵심 꿀팁입니다.)

3. 기본 뼈대의 크기: flex-basis

Flexbox 환경에서 width 속성보다 우선순위가 높은 '아이템의 기본 크기'를 지정합니다. flex-direction이 row(가로)일 때는 너비를, column(세로)일 때는 높이를 제어하는 영리한 속성입니다. 기본값은 auto(자신의 내용물 크기만큼)입니다.

4. 전문가의 코드: flex 축약 속성 (Shorthand)

위의 세 가지 속성(grow, shrink, basis)을 매번 따로 적는 것은 매우 비효율적입니다. 실무에서는 이 3가지를 한 단어 flex로 묶어서 사용합니다.

/* flex: <grow> <shrink> <basis> 순서입니다. */
.item {
    flex: 1 1 0; /* 공간 남으면 1비율로 커지고, 모자라면 찌그러지며, 기본 크기는 0으로 무시 */
}

/* 🚀 너무 자주 쓰여서 축약형 단축키까지 존재합니다 */
.item-auto { flex: auto; } /* 1 1 auto 와 동일 (자유자재 탄성) */
.item-none { flex: none; } /* 0 0 auto 와 동일 (절대 크기 변하지 않음) */

5. 나 홀로 독고다이 정렬: align-self

부모가 align-items: center;로 모든 자식을 수직 중앙 정렬로 지시했더라도, "나는 삐딱하게 혼자 맨 위에 붙고 싶다!"라고 반항하는 아이템이 있다면 align-self를 사용합니다.

.rebel-item {
    align-self: flex-start; /* 부모의 통제를 벗어나 혼자 위로 찰싹 붙음 */
}

정리하며

부모의 display: flex가 무대를 만들었다면, 자식들의 flex: 1 속성은 그 무대를 꽉 채우는 연기자들의 애드리브와 같습니다. 특히 입력창(Input) 옆에 고정 크기의 버튼(Button)을 두는 UI나, 사진 옆에 글씨가 빈 곳을 채우는 카드형 UI를 만들 때 이 `flex-grow`의 유연함은 절대적인 힘을 발휘합니다. Flexbox의 모든 문법을 통달했으니, 이제 실전에서 이 무기들을 조합해 볼 차례입니다. 다음이번 포스팅에서는 현업 프론트엔드 실무에서 숨 쉬듯 만들어내는 "실무에서 자주 쓰이는 Flexbox UI 패턴 5가지"의 코드를 뼈 때리게 파헤쳐 보겠습니다!


실무에서 자주 쓰이는 Flexbox UI 패턴 5가지 완벽 정복

Flexbox의 문법(Container와 Item 속성)을 완벽히 암기했다 하더라도, 막상 피그마(Figma) 디자인 시안을 던져주고 코드로 구현하라고 하면 눈앞이 하얘지는 초보 퍼블리셔들이 많습니다. "어? 여기엔 space-between을 써야 하나? flex-grow를 줘야 하나?" 문법과 실전은 완전히 다른 영역이기 때문입니다. 현대 웹사이트의 컴포넌트들을 분석해 보면, 수천 가지의 화려한 UI도 결국 Flexbox를 이용한 5~6가지의 전형적인 레이아웃 패턴의 반복에 불과하다는 것을 깨닫게 됩니다. 이번 글에서는 글로벌 대기업 웹사이트부터 개인 블로그까지 빠짐없이 등장하는 실무 최다 빈출 Flexbox UI 패턴 5가지의 구현 원리와 코드를 상세히 알아보겠습니다. 이 패턴들만 외워두면 어떤 디자인 시안이 주어져도 1분 안에 HTML 뼈대를 찍어낼 수 있습니다.

패턴 1: 양끝 정렬 GNB (네비게이션 바)

왼쪽에는 회사 로고가 있고, 오른쪽에는 회원가입/로그인 버튼이 있는 전형적인 상단 헤더 메뉴입니다. 과거에는 Float로 양쪽으로 찢었지만, 이제는 space-between 하나로 종결됩니다.

.header-nav {
    display: flex;
    justify-content: space-between; /* 💡 핵심: 양끝으로 자식들을 밀어냄 */
    align-items: center;            /* 수직 중앙 정렬 */
    padding: 0 20px;
}

패턴 2: 꽉 차는 검색창 (Search Input & Button)

검색 폼에서 '검색 버튼'은 고정된 크기를 유지하고, '텍스트 입력창(Input)'은 화면이 늘어남에 따라 남는 공간을 고무줄처럼 모두 독식하게 만드는 모바일 반응형의 핵심 패턴입니다.

.search-form {
    display: flex; /* 요소들을 한 줄로 */
}
.search-input {
    flex-grow: 1;  /* 💡 핵심: 내가 남는 공간 다 먹을게! (팽창) */
    padding: 10px;
}
.search-btn {
    flex-shrink: 0; /* 💡 핵심: 창이 좁아져도 난 절대 안 찌그러질거야! */
    width: 80px;
}

패턴 3: 미디어 오브젝트 (Media Object)

페이스북 피드, 유튜브 댓글창처럼 왼쪽에 둥근 '프로필 이미지'가 고정되어 있고, 오른쪽에 '텍스트(이름, 내용)'가 유연하게 채워지는 전 세계 공통 UI 패턴입니다.

.media-card {
    display: flex;
    align-items: flex-start; /* 프로필과 텍스트를 위쪽으로 맞춤 */
    gap: 15px;               /* 💡 핵심: 최신 gap 속성으로 요소 간 깔끔한 여백 부여 */
}
.profile-img {
    flex-shrink: 0; /* 이미지가 텍스트에 밀려 찌그러지는 현상 방지 */
    width: 50px; height: 50px; border-radius: 50%;
}
.content-text {
    flex-grow: 1; /* 긴 텍스트가 남은 공간을 차지하며 예쁘게 줄바꿈됨 */
}

패턴 4: 하단 고정 푸터 (Sticky Footer)

웹사이트 콘텐츠(본문) 내용이 너무 적어서 푸터(바닥글)가 화면 중간에 붕 떠버리는 흉측한 경험을 해보셨을 겁니다. vhflex-direction: column을 조합하면 콘텐츠 길이와 무관하게 푸터를 바닥에 찰싹 고정할 수 있습니다.

body {
    display: flex;
    flex-direction: column; /* 세로로 쌓기 */
    min-height: 100vh;      /* 최소 높이를 화면 꽉 차게 설정 */
}
.main-content {
    flex-grow: 1; /* 💡 핵심: 본문이 남는 세로 여백을 다 밀어내어 푸터를 바닥으로 쫓아냄! */
}
.footer {
    height: 100px; /* 고정 높이 */
}

패턴 5: N등분 갤러리 썸네일 그리드 (Wrap 활용)

인스타그램 피드나 쇼핑몰 상품 리스트처럼, 한 줄에 3개씩(혹은 4개씩) 일정한 크기로 카드를 배치하고 모자라면 아래로 예쁘게 줄바꿈(Wrap) 시키는 기법입니다.

.product-list {
    display: flex;
    flex-wrap: wrap; /* 💡 핵심: 넘치면 아래로 줄바꿈! */
    gap: 20px;
}
.product-item {
    /* 3등분(33.333%)에서 여백(gap) 크기를 빼서 균등 분배 */
    flex-basis: calc(33.333% - 20px); 
}

(최근에는 이러한 2차원 바둑판 배치는 CSS Grid를 사용하는 것이 훨씬 더 강력하고 권장되지만, 레거시 호환성을 위해 Flexbox Wrap 패턴도 반드시 알아두어야 합니다.)

정리하며

이 5가지의 Flexbox 마스터 템플릿만 손과 머리에 완전히 박아둔다면, 여러분은 복잡한 와이어프레임을 마주해도 당황하지 않고 레고 블록 조립하듯 뼈대를 뚝딱 완성해 낼 수 있습니다. 자, 1차원 선(줄) 단위의 정렬을 완벽하게 끝냈으니 이제 가로와 세로, 2차원의 공간을 동시에 조각하는 괴물 같은 기술을 맞이할 시간입니다. 다음이번 포스팅에서는 복잡한 바둑판 레이아웃을 한 줄로 끝내버리는 궁극의 병기, "CSS Grid Layout의 탄생과 컨테이너 기본 문법"에 대해 상세히 파헤쳐 보겠습니다!

반응형