Skip to content
This page has been auto-translated and may contain errors.View in English

Flexbox

docs.scrimba.com

세 개의 버튼을 한 행에 배치하되, 고르게 간격을 두고, 모두 같은 높이로, 각 버튼의 텍스트 양에 관계없이 수직 중앙에 정렬하고 싶습니다. 예전에는 이를 위해 float, clearfix, 그리고 많은 추측이 필요했습니다. Flexbox는 정확히 이 목적으로 만들어진 도구입니다. 한 컨테이너에 자식 요소를 한 줄로 배치하도록 지시한 후, 두 축을 따라 요소들을 조정하여 원하는 위치에 배치합니다. 웹에서 볼 수 있는 대부분의 일상적인 레이아웃(네비게이션 바, 툴바, 카드 행)은 내부적으로 flex 컨테이너를 사용합니다.

flex 컨테이너

Flexbox는 부모 요소에 한 줄의 코드로 시작합니다. 컨테이너에 display: flex를 설정하면 그 직접 자식 요소들이 한 행에 나란히 배치됩니다. 그 컨테이너는 이제 **flex 컨테이너**이고, 그 안의 각 자식은 flex 항목이 됩니다.

css
.nav {
  display: flex;    /* 자식 요소들이 이제 한 행으로 배치됩니다 */
}

항목들은 두 방향으로 배치됩니다. **주축(main axis)**은 왼쪽에서 오른쪽으로 실행되며, 항목들이 배치되는 방식입니다. **교차축(cross axis)**은 위에서 아래로 실행되며, 행을 가로지릅니다. 두 축을 따라 항목들을 조정할 것이므로, 지금 이를 시각화하는 것이 도움이 됩니다. 주축은 항목들이 앉아 있는 선이고, 교차축은 그것을 가로지르는 방향입니다.

display: flex는 요소를 **flex 컨테이너**로 만들고 그 직접 자식을 flex 항목으로 만듭니다. 직접 자식만 관련이 있으며, 더 깊게 중첩된 것은 자신의 부모에 의해 배치됩니다. 기본적으로 항목들은 왼쪽에서 오른쪽으로 한 행에 앉으며, 각각은 그 내용의 너비로 축소됩니다.

css
.nav {
  display: flex;    /* 직접 자식이 flex 항목의 행이 됩니다 */
}

전체 모델은 두 축으로 실행됩니다. **주축(main axis)**은 항목들이 흐르는 방향이며, 기본적으로 한 행이므로 왼쪽에서 오른쪽입니다. **교차축(cross axis)**은 이에 수직이며, 위에서 아래로 실행됩니다. 만나는 모든 정렬 속성은 한 축이나 다른 축에서 작동하므로, 두 축을 명확히 유지하는 것이 나머지를 이해하는 데 핵심입니다.

display: flex는 요소에 **flex 포맷 컨텍스트**를 제공합니다. 그 직접 자식은 flex 항목이 되고 flex 알고리즘에 의해 배치되며, 일반 흐름이 아닙니다. 직접 자식만 참여하며, 텍스트 실행과 중첩된 자손은 그 아래에서 처리됩니다. 이는 마진 붕괴를 중지하는 것과 같은 종류의 경계이며, flex 레이아웃이 float와 clear 시대보다 더 예측 가능하게 작동하는 이유 중 하나입니다.

css
.nav {
  display: flex;    /* flex 포맷 컨텍스트를 설정합니다 */
}

두 축이 모든 것을 지배합니다. **주축(main axis)**은 flex-direction으로 설정되며(기본적으로 한 행이므로 인라인 시작에서 인라인 끝), 교차축은 이에 수직입니다. 이 구분은 미적이 아닙니다. justify-content는 항상 주축을 따라 작동하고 align-items는 항상 교차축을 따라 작동하므로, flex-directioncolumn으로 바꾸는 순간, 이 두 속성은 밀어내는 방향을 바꿉니다. "수평"과 "수직"이 아닌 축으로 레이아웃의 이름을 지정하는 것이 방향이 바뀔 때 일관성을 유지하는 방법입니다.

css
.nav {
  display: flex;
}

단 하나의 선언으로, 모든 블록의 자식들은 위에서 아래로 쌓이는 것을 멈추고 한 행으로 앉기 시작합니다. 이 장의 나머지는 항목들이 컨테이너에 있을 때 조정하는 것에 대한 내용입니다.

Junoflex 컨테이너 부모에 display: flex를 설정하면 그 직접 자식이 한 행으로 배치됩니다. 그 부모는 flex 컨테이너이고, 자식들은 flex 항목입니다. 항목들은 두 방향으로 이동합니다. 주축은 항목들이 앉아 있는 선이고, 교차축은 그것을 가로지르며, 당신은 두 축을 따라 항목들을 밀어낼 것입니다.
Junoflex 컨테이너display: flex는 컨테이너가 그 직접 자식을 flex 항목의 행으로 배치하게 합니다. 직접 자식만 참여하며, 더 깊게 중첩된 것은 참여하지 않습니다. 두 축을 명확히 유지하세요. 주축은 흐름 방향이고, 교차축은 수직이며, 모든 정렬 속성은 하나 또는 다른 축에서 작동합니다.
Junoflex 컨테이너display: flex는 flex 포맷 컨텍스트를 시작하므로 직접 자식은 flex 알고리즘으로 배치되고 마진은 그 내부에서 붕괴하지 않습니다. 수평과 수직이 아닌 축으로 레이아웃의 이름을 지으세요. justify-content는 주축을 따라가고 align-items는 교차축을 따라가기 때문입니다. flex-directioncolumn으로 바꾸면 두 속성은 밀어내는 방향을 바꿉니다.

축을 따라 정렬

항목들이 한 행에 배치되면, 두 속성이 항목들을 움직입니다. **justify-content**는 주축(항목들이 앉아 있는 방향)을 따라 항목들 사이에 간격을 둡니다. align-items는 교차축, 즉 행 내에서 위 아래로 항목들을 이동시킵니다.

css
.nav {
  display: flex;
  justify-content: space-between;   /* 행을 따라 항목들을 밀어냅니다 */
  align-items: center;              /* 수직 중앙에 정렬합니다 */
}

justify-content의 일반적인 값은 flex-start(왼쪽에 모음), center(중앙에 모음), flex-end(오른쪽에 모음), space-between(항목 사이에 간격, 끝에는 없음), space-around(각 항목의 양쪽에 간격)입니다. align-items의 경우 center가 가장 자주 사용됩니다.

무언가를 양쪽 방향으로 중앙에 정렬하려면, 누구나 배우는 첫 번째 이동입니다. 둘 다 center로 설정하세요.

css
.hero {
  display: flex;
  justify-content: center;   /* 주축을 따라 중앙에 정렬 */
  align-items: center;       /* 교차축을 따라 중앙에 정렬 */
}

두 속성은 정렬을 처리하며, 축마다 하나씩입니다. **justify-content**는 주축을 따라 항목들을 분배하고, align-items는 교차축에 항목들을 배치합니다. 다른 축을 소유하므로 서로 충돌하지 않으며, 수직 방향을 가리킵니다.

css
.nav {
  display: flex;
  justify-content: space-between;   /* 주축을 따라 항목들을 펼칩니다 */
  align-items: center;              /* 교차축에 중앙에 정렬합니다 */
}

justify-content의 경우, 알아야 할 값은 flex-start, center, flex-end, space-between(항목 사이에 같은 간격, 끝에는 붙음), space-around(각 항목 주변에 같은 공간, 따라서 끝 간격은 중간 간격의 절반)입니다. align-items의 경우, 기본값은 stretch이며, 이는 모든 항목이 컨테이너의 높이를 채우게 하며, 이것이 카드 행이 내용이 다르더라도 같은 높이로 나오는 이유입니다. align-items: center로 설정하면 항목들은 내용 높이로 축소되고 대신 중앙에 앉습니다.

양쪽 축에 중앙 정렬을 하는 것은 flexbox를 유명하게 만드는 속성 쌍입니다.

css
.hero {
  display: flex;
  justify-content: center;   /* 주축 */
  align-items: center;       /* 교차축 */
}

정렬은 축으로 깔끔하게 나뉩니다. **justify-content**는 주축을 따라 여유 공간을 분배하고, align-items는 모든 항목의 기본 교차축 위치를 설정합니다. 수직 축에서 작동하므로 충돌할 수 없지만, 둘 다 어느 방향이 "주"인지에 따라 결정되므로, flex-direction: column은 각각이 제어하는 것을 바꿉니다.

css
.nav {
  display: flex;
  justify-content: space-between;   /* 여유 공간이 항목 사이에 배치됩니다 */
  align-items: center;              /* 각 항목이 교차축에 중앙 정렬됩니다 */
}

사람들을 헷갈리게 하는 구분은 justify-content가 주축에 남은 공간이 있을 때만 작동한다는 것입니다. 여유 공간을 분배하므로, 항목들이 이미 컨테이너를 채우거나 오버플로우하면 space-betweencenter는 배치할 것이 없으므로 동일하게 보입니다. 반대로 align-items는 컨테이너의 교차 크기 내에서 각 항목을 독립적으로 배치하며, 그 초기 값은 stretch입니다. 고정된 교차축 크기가 없는 항목들은 컨테이너를 채우기 위해 성장합니다. 같은 높이의 카드 행은 align-items: stretch가 기본 작업을 하는 것입니다. 아래의 크기 섹션에서 다루는 align-self로 항목별로 이를 재정의합니다.

css
.hero {
  display: flex;
  justify-content: center;   /* 주축 중앙 정렬 */
  align-items: center;       /* 교차축 중앙 정렬, stretch 기본값을 재정의 */
}

두 항목과 컨테이너의 min-height, 둘 다 center로 설정되면, 개발자 세대가 절대 위치와 음수 마진으로 조작해야 했던 중앙 정렬 문제를 해결했습니다.

Juno축을 따라 정렬justify-content는 주축을 따라 항목들 사이에 간격을 두고, align-items는 교차축을 따라 항목들을 이동시킵니다. 첫 번째의 값 중에 기억할 것은 center, space-between, flex-start입니다. 둘 다 center로 설정하면 내부의 모든 것이 정확히 중앙에 앉으며, 이는 당신이 계속 사용할 레이아웃 이동입니다.
Juno축을 따라 정렬 축당 하나의 속성: 주축에는 justify-content, 교차축에는 align-items. 기본 align-items: stretch는 카드 행이 당신이 요청하지 않았는데도 같은 높이로 나오는 이유입니다. 그리고 둘 다 center로 설정하는 것은 중앙에 정렬하는 이동이며 기억할 가치가 있습니다.
Juno축을 따라 정렬justify-content는 남은 주축 공간을 분배하므로, 항목들이 이미 행을 채우면 아무것도 하지 않으며, 이것이 "왜 이것이 중앙 정렬이 안 되지" 순간의 많은 부분을 설명합니다. align-items는 교차축에 각 항목을 배치하고 기본적으로 stretch로, 무료로 같은 높이의 행을 제공합니다. flex-direction을 바꾸고 두 속성이 작동하는 축을 바꾼다는 것을 기억하세요.

방향과 래핑

기본적으로 flex 컨테이너는 항목들을 한 행으로 배치합니다. **flex-direction**으로 이를 변경하세요. column으로 설정하면 항목들이 나란히 앉아 있는 대신 위에서 아래로 쌓입니다.

css
.sidebar {
  display: flex;
  flex-direction: column;   /* 항목들이 이제 수직으로 쌓입니다 */
}

한 행의 항목들이 공간이 부족하면, 더 얇아지고 더 얇아집니다. 대신 새로운 줄로 떨어지도록 하려면 flex-wrap: wrap을 추가하세요.

css
.card-row {
  display: flex;
  flex-wrap: wrap;   /* 맞지 않는 항목들이 다음 줄로 이동합니다 */
}

항목 사이의 공간을 위해 gap을 사용하세요. 바깥쪽 가장자리에 공간을 추가하지 않으면서 모든 항목 사이에 일관된 간격을 추가합니다.

css
.card-row {
  display: flex;
  gap: 16px;   /* 각 항목 사이에 16px */
}

**flex-direction**은 주축을 설정합니다. 기본 row는 왼쪽에서 오른쪽으로 실행됩니다. column은 주축을 수직으로 만들므로, 항목들이 위에서 아래로 쌓이고, 중요하게도, justify-content는 이제 수직 간격을 제어하고 align-items는 수평을 제어합니다. 순서를 뒤집어야 한다면 row-reversecolumn-reverse도 있습니다.

css
.sidebar {
  display: flex;
  flex-direction: column;   /* 주축이 이제 수직입니다 */
  justify-content: center;  /* 즉, 이것은 수직으로 중앙 정렬합니다 */
}

기본적으로 flex 줄은 절대 끊어지지 않습니다. 항목들은 래핑하지 않고 맞도록 축소됩니다. flex-wrap: wrap을 설정하면 맞지 않는 항목들이 새로운 줄로 이동하며, 이것이 미디어 쿼리 없이 반응형 카드 그리드를 가능하게 합니다.

css
.card-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;   /* gap은 두 축에서 작동합니다: 행과 열 사이에 16px */
}

항목에 대한 마진 대신 gap을 간격에 사용하세요. gap은 항목 사이에만 적용되며, 절대 바깥쪽 가장자리에는 적용되지 않으므로, 마지막 자식에서 후행 마진을 제거할 필요가 없습니다.

**flex-direction**은 주축을 정의하고, 모든 축 종속 속성이 이를 따릅니다. row(기본값)는 주축을 수평으로 만들고, column은 주축을 수직으로 만들며 조용히 justify-content를 수직 간격으로, align-items를 수평으로 재할당합니다. -reverse 변형은 주축의 방향을 뒤집지만, 시각적으로만 재정렬된다는 점에 주목하세요. DOM 순서는 변하지 않으므로 키보드와 스크린 리더 순서는 여전히 소스를 따르며, 이는 row-reverse에 도달할 때의 진정한 접근성 고려사항입니다.

css
.sidebar {
  display: flex;
  flex-direction: column;    /* 주축이 수직; justify-content는 이제 수직으로 중앙 정렬 */
  gap: 8px;
}

flex-wrap: wrap은 단일 줄 제한을 해제합니다. 없으면, flex 컨테이너는 모든 항목을 한 줄에 강제로 배치하고 부족분을 축소하여 배포합니다. 있으면, 주 크기를 오버플로우하는 항목들은 새 줄로 끊어지고, 컨테이너는 다중 줄이 됩니다. 래핑이 켜지면, align-content(align-items와 구별됨)는 교차축에서 줄들의 간격을 지배합니다. gap은 항목 사이의 공간을 설정하고, 래핑할 때는 줄 사이의 공간도 설정하며, 이는 올바른 도구입니다. 마진과 달리 아무것도 붕괴하지 않고, 가장자리 공간을 추가하지 않으며, 단일 간격 결정으로 읽힙니다.

css
.card-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 24px;   /* row-gap 16px, column-gap 24px */
}

이것이 또한 CSS Grid와의 경계가 나타나는 곳입니다. Flex 래핑은 줄을 채우고 나서 끊어지므로, 다른 행의 항목들은 열로 정렬되지 않습니다. 정렬된 행과 열을 가진 진정한 2차원 그리드가 필요할 때, 그것은 flexbox가 아닌 grid의 일입니다.

Juno방향과 래핑flex-direction: column은 항목들을 한 행 대신 수직으로 쌓습니다. flex-wrap: wrap은 공간이 부족하면 항목들이 새로운 줄로 떨어지도록 하며, 짜내는 대신입니다. 그리고 gap은 가장자리에는 추가하지 않고 항목들 사이에만 공간을 두므로, 마진 전에 이를 사용하세요.
Juno방향과 래핑flex-direction은 주축을 설정하고, column으로 전환하면 justify-content는 이제 수직으로 간격을 두므로, 이는 한 번 사람들을 놀라게 합니다. flex-wrap: wrap은 미디어 쿼리 없이 카드 행을 리플로우하게 하는 것입니다. gap을 간격에 사용하여 마지막 항목에서 잃어버린 마진을 절대 추적하지 않도록 하세요.
Juno방향과 래핑flex-direction은 주축을 정의하고 모든 축 기반 속성이 이를 따르며, -reverse 값은 시각적으로 재정렬하지만 DOM과 포커스 순서는 그대로 두므로 주의해서 사용하세요. flex-wrap은 컨테이너를 다중 줄로 만들고 줄 간격을 align-content에 넘깁니다. 래핑된 항목들이 실제 열로 정렬되어야 할 때, 그것은 flexbox가 아닌 grid입니다.

유연한 항목 크기

Flexbox의 요점은 항목들이 유연하게 성장하거나 축소하여 공간을 공유할 수 있다는 것입니다. 당신이 가장 자주 사용할 약식은 항목에 대한 flex: 1이며, 이는 항목이 성장하고 이용 가능한 공간의 동일한 몫을 취하도록 지시합니다.

css
.card {
  flex: 1;   /* 모든 카드가 성장하여 행의 동일한 몫을 채웁니다 */
}

행의 세 카드에 flex: 1을 설정하면 컨테이너를 세 개의 동일한 너비로 분할합니다. 한 카드에 flex: 2를 주면 다른 카드보다 두 배의 공간을 차지합니다. 그 하나의 숫자는 항목들이 그들 사이의 남은 공간을 어떻게 나누는지입니다.

flex: 1 뒤에는 세 개의 별도 제어가 있습니다. 항목이 얼마나 성장하는지, 얼마나 축소하는지, 그리고 시작 크기입니다. 처음에는 하나씩 설정하는 경우가 드물며, 약식은 일반적인 경우를 다루지만, 그것들이 있다는 것을 아는 것은 도움이 됩니다.

세 속성은 항목들이 공간을 어떻게 공유하는지 결정합니다. **flex-grow**는 항목이 남은 공간을 채우기 위해 얼마나 성장하는지를 설정합니다(0은 성장하지 않음을 의미합니다). flex-shrink는 공간이 부족할 때 항목이 얼마나 포기하는지를 설정합니다(기본값 1은 축소될 수 있음을 의미합니다). flex-basis는 성장하거나 축소하기 전에 항목의 시작 크기를 설정하며, 기본값은 auto이며, "내용 또는 너비 사용"을 의미합니다.

flex 약식은 세 가지를 모두 번들로 제공하며, 당신이 실제로 입력하는 값은 몇 가지입니다.

css
.card {
  flex: 1;   /* grow 1, shrink 1, basis 0: 동일 너비 열 */
}

.sidebar {
  flex: 0 0 240px;   /* 성장하지 않고, 축소하지 않고, 240px 유지 */
}

flex: 1은 워크호스입니다. 내용에 관계없이 행을 동일한 몫으로 나누며, 0 basis는 아무것도 시작하지 않고 grow 인수로만 성장하기 때문입니다. flex: 0 0 240pxflex: 1 주 영역 옆의 고정 너비 사이드바이며, 지속적으로 구축할 레이아웃입니다.

항목 크기는 컨테이너가 순서대로 평가하는 세 속성을 통해 해결됩니다. **flex-basis**는 항목의 시작 주축 크기이며, 여유 공간이 분배되기 전에 취해집니다. 기본 auto는 항목의 width(또는 내용 크기)를 연기합니다. 그 다음 컨테이너는 basis 값의 합과 자신의 크기 사이의 차이를 측정합니다. 여유 공간이 있으면, 각 항목의 flex-grow 비율로 배포됩니다. 부족이 있으면, 각 항목의 basis로 가중된 flex-shrink 비율로 반환됩니다.

css
/* flex: 1은 flex-grow: 1, flex-shrink: 1, flex-basis: 0%로 확장됩니다 */
.card {
  flex: 1;   /* basis 0이므로 항목은 내용 너비를 무시하고 grow 인수로 공간을 분할합니다 */
}

미묘한 부분은 flex-basiswidth입니다. 상호작용하기 때문입니다. flex-basis: 0(flex: 1에서처럼)은 항목들이 내용을 무시하고 grow 인수로만 공간을 나누도록 하여 진정한 동일 열을 제공합니다. flex-basis: auto(flex: auto 또는 일반 width에서처럼)는 각 항목이 내용 또는 선언된 너비에서 시작하고 오직 그 다음 나머지를 공유하도록 하므로, 더 많은 내용이 있는 항목들이 더 넓어집니다. 둘 사이의 선택은 정말로 내용이 최종 너비에 영향을 미쳐야 하는지에 대한 선택입니다.

두 가지 프로덕션 참고 사항. 첫째, flex-basis는 둘 다 설정되면 width를 이기므로, 항목이 flex 항목이 되면 flex를 통해 크기를 표현하는 것을 선호하세요. 둘째, 오버플로우 주의: flex 항목은 기본 min-width: auto을 가지므로, 내용의 고유 크기보다 축소하기를 거부하므로, 긴 단어 또는 오버플로우하는 자식이 전체 행을 날려버릴 수 있습니다. 수정은 축소되어야 하는 항목에서 min-width: 0입니다.

css
.main {
  flex: 1;
  min-width: 0;   /* 이 항목이 내용 아래로 축소되도록 하여, 긴 텍스트가 오버플로우하지 않고 잘리도록 합니다 */
}

align-self는 단일 항목에 대해 align-items를 재정의하므로, 한 항목은 flex-start에 앉을 수 있고 나머지는 중앙 정렬됩니다. 그리고 도구 호출: 1차원 레이아웃인 네비게이션 바, 툴바, 단일 행 또는 열의 항목에 flexbox를 사용하세요. 정렬된 행 열이 동시에 필요하면, CSS Grid가 올바른 도구입니다. 이 모든 것 아래에서 너비가 어떻게 해결되는지 불확실하면, 크기 단위가 여기서 백분율과 다른 단위가 어떻게 작동하는지를 다룹니다.

css
.layout {
  display: flex;
  gap: 24px;
}
.sidebar {
  flex: 0 0 240px;   /* 고정 240px, 절대 성장하거나 축소하지 않음 */
}
.main {
  flex: 1;           /* 남은 모든 공간을 차지합니다 */
}

고정 사이드바 옆의 유연한 주 열, 의도의 세 줄. 이 하나의 패턴과 앞의 정렬된 네비게이션 바는 당신이 구축할 레이아웃의 큰 부분을 다룹니다.

Juno유연한 항목 크기 항목에 대한 flex: 1은 항목이 성장하고 행의 동일한 몫을 차지하도록 지시하므로, flex: 1을 가진 세 카드는 같은 너비로 나옵니다. 하나를 flex: 2로 올리면 두 배의 공간을 차지합니다. 그 하나의 숫자는 flex 항목들이 그들 사이의 공간을 어떻게 분할하는지입니다.
Juno유연한 항목 크기flex 약식은 성장, 축소, basis를 번들로 제공합니다. flex: 1은 동일 너비 열을 제공하는데, 그것의 0 basis는 항목들이 아무것도 시작하지 않고 고르게 성장하기 때문입니다. flex: 0 0 240pxflex: 1 주 영역 옆의 고정 사이드바이며, 반복해서 도달할 레이아웃입니다.
Juno유연한 항목 크기flex-basis는 공간이 공유되기 전의 시작 크기이며, flex 항목에 설정되면 width를 이기므로, flex: 1(basis 0)은 공간을 고르게 분할하는 반면 flex: auto는 내용이 너비에 영향을 미치게 합니다. 항목이 내용 아래로 축소되는 것을 거부하는 기본 min-width: auto를 조심하므로, 그 행을 오버플로우할 때까지 min-width: 0을 설정하세요. 정렬에서 한 항목을 벗겨내려면 align-self를 사용하고, 정렬된 행과 열이 필요한 순간 grid로 전환하세요.