현록

CSS flex justify-content와 align-items 차이

Flexbox로 요소를 가운데 정렬할 때 justify-contentalign-items를 함께 사용한다.
두 속성 모두 정렬을 담당하지만 기준이 되는 축이 다르다.

justify-content는 주축에서 flex item을 정렬한다.
align-items는 주축과 직각인 교차축에서 flex item을 정렬한다.

처음에는 justify-content는 가로, align-items는 세로라고 외우기 쉽다.
하지만 flex-directioncolumn으로 바뀌면 두 방향도 함께 바뀐다.
그래서 가로와 세로보다 주축과 교차축으로 이해하는 편이 정확하다.

flex container와 flex item

Flexbox 정렬을 사용하려면 먼저 부모 요소를 flex container로 만들어야 한다.

<div class="container">
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item">C</div>
</div>
.container {
  display: flex;
}

display: flex가 적용된 .container가 flex container다.
그 바로 아래 자식인 .item 세 개가 flex item이 된다.

justify-contentalign-items는 기본적으로 부모인 flex container에 작성한다.
자식에 속성을 적으면 원하는 정렬이 일어나지 않는 경우가 많다.

display가 요소의 바깥 배치에 미치는 영향은 CSS display block inline inline-block 차이에서 별도로 정리했다.

주축과 교차축

Flexbox에는 정렬의 기준이 되는 두 축이 있다.

  • 주축인 main axis는 flex item이 나열되는 방향이다.
  • 교차축인 cross axis는 주축과 직각을 이루는 방향이다.

주축은 flex-direction이 결정한다.
기본값인 row에서는 item이 왼쪽에서 오른쪽으로 놓이므로 가로가 주축이다.
세로는 교차축이 된다.

.container {
  display: flex;
  flex-direction: row;
}

이 상태에서는 justify-content가 가로 정렬을 담당한다.
align-items는 세로 정렬을 담당한다.

.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

flex-direction: column으로 바꾸면 item이 위에서 아래로 놓인다.
세로가 주축이 되고 가로가 교차축이 된다.

.container {
  display: flex;
  flex-direction: column;
}

이제 justify-content는 세로 정렬이고 align-items는 가로 정렬이다.

justify-content의 역할

justify-content는 flex container의 주축에 남은 공간을 어떻게 배분할지 정한다.
item을 시작점, 가운데, 끝점에 모으거나 item 사이에 공간을 나눌 수 있다.

.container {
  display: flex;
  justify-content: center;
}

기본 flex-direction: row에서는 item들이 가로 방향 가운데에 모인다.

자주 사용하는 값은 다음과 같다.

.container {
  justify-content: flex-start;
}

flex-start는 item을 주축의 시작점에 모은다.
Flexbox에서 기본적으로 보이는 배치다.

.container {
  justify-content: flex-end;
}

flex-end는 item을 주축의 끝점에 모은다.

.container {
  justify-content: center;
}

center는 item 묶음을 주축 가운데에 놓는다.

.container {
  justify-content: space-between;
}

space-between은 첫 item을 시작점에, 마지막 item을 끝점에 놓는다.
남은 공간은 item 사이에만 같은 크기로 나눈다.

.container {
  justify-content: space-around;
}

space-around는 각 item의 양쪽에 같은 크기의 공간을 배정한다.
그 결과 container 가장자리의 공간은 item 사이 공간의 절반처럼 보인다.

.container {
  justify-content: space-evenly;
}

space-evenly는 container 가장자리와 모든 item 사이의 공간을 같은 크기로 만든다.

align-items의 역할

align-items는 flex item을 교차축에서 정렬한다.
한 flex line 안에서 모든 item의 기본 정렬을 한 번에 지정할 때 사용한다.

.container {
  display: flex;
  min-height: 200px;
  align-items: center;
}

기본 flex-direction: row에서는 교차축이 세로다.
따라서 item들이 container의 세로 가운데에 놓인다.

자주 사용하는 값은 다음과 같다.

.container {
  align-items: stretch;
}

stretch는 cross size가 auto인 item을 교차축 방향으로 늘린다.
Flexbox에서 align-items의 기본 동작으로 자주 보이는 값이다.

.container {
  align-items: flex-start;
}

flex-start는 item을 교차축의 시작점에 놓는다.

.container {
  align-items: flex-end;
}

flex-end는 item을 교차축의 끝점에 놓는다.

.container {
  align-items: center;
}

center는 item을 교차축 가운데에 놓는다.

.container {
  align-items: baseline;
}

baseline은 item 안의 텍스트 기준선을 맞춘다.
글자 크기가 서로 다른 메뉴나 가격 표시를 정렬할 때 유용하다.

두 속성의 핵심 차이

두 속성은 가로와 세로가 아니라 축을 기준으로 구분한다.

  • justify-content는 주축의 남은 공간을 배분한다.
  • align-items는 교차축에서 각 item의 기본 정렬을 정한다.
  • 주축은 flex-direction을 따라간다.
  • 교차축은 주축과 직각이다.
  • 두 속성은 flex item이 아니라 flex container에 작성한다.

row에서는 justify-content가 가로, align-items가 세로다.
column에서는 justify-content가 세로, align-items가 가로다.

이 두 문장만 기억해도 대부분의 정렬 문제를 풀 수 있다.

가로와 세로 가운데 정렬

부모 안에서 자식을 가로와 세로 모두 가운데에 놓으려면 두 속성에 center를 지정한다.

<div class="box">
  <span>가운데</span>
</div>
.box {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 320px;
  height: 180px;
  border: 1px solid #d8dee4;
}

justify-content: center는 주축 가운데를 담당한다.
align-items: center는 교차축 가운데를 담당한다.

row에서는 결과적으로 가로와 세로 가운데 정렬이 된다.
column에서도 두 축 모두 center이므로 화면에 보이는 결과는 같은 가운데 정렬이다.

container에 item보다 큰 높이가 없다면 세로 방향의 남은 공간도 없다.
이 경우 align-items: center를 추가해도 움직임이 잘 보이지 않을 수 있다.

flex-direction row의 정렬 기준

flex-direction: row는 기본값이다.
item이 문서의 inline 방향을 따라 한 줄로 배치된다.

.toolbar {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
}

이 toolbar에서 justify-content: space-between은 가로 남은 공간을 양쪽에 배치한다.
align-items: center는 높이가 다른 item을 세로 가운데에 맞춘다.

헤더의 로고와 메뉴를 양쪽 끝에 놓거나, 카드 제목과 버튼을 한 줄에 배치할 때 자주 쓰는 조합이다.

<header class="toolbar">
  <strong>프로젝트</strong>
  <button type="button">설정</button>
</header>
.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  min-height: 56px;
  padding-inline: 16px;
}

안쪽 여백과 바깥 간격의 기준이 헷갈린다면 CSS margin과 padding 차이를 함께 확인하면 좋다.

flex-direction column의 정렬 기준

flex-direction: column에서는 item이 위에서 아래로 놓인다.
주축이 세로로 바뀌기 때문에 두 정렬 속성의 화면상 방향도 바뀐다.

.empty-state {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  min-height: 320px;
}

justify-content: center는 콘텐츠 묶음을 세로 가운데에 놓는다.
align-items: center는 각 item을 가로 가운데에 놓는다.

<div class="empty-state">
  <strong>표시할 항목이 없습니다.</strong>
  <button type="button">새 항목 만들기</button>
</div>

텍스트와 버튼을 세로로 쌓으면서 전체를 화면 가운데에 놓는 빈 상태 UI에 잘 맞는다.

column-reverserow-reverse를 사용하면 시작점과 끝점도 반대로 바뀐다.
단순히 화면 위치만 보고 flex-startflex-end를 외우면 reverse 값에서 헷갈릴 수 있다.

justify-content가 적용되지 않는 원인

justify-content는 주축에 남은 공간이 있어야 눈에 보이는 효과를 만든다.
item이 container를 이미 가득 채우면 배분할 공간이 없다.

.item {
  flex: 1;
}

모든 item에 flex: 1을 주면 item이 남은 공간을 나눠 가진다.
이 상태에서는 justify-content: space-between을 추가해도 item 사이에 새로 배분할 여유 공간이 거의 없을 수 있다.

다음 항목을 순서대로 확인하면 원인을 찾기 쉽다.

  1. 속성을 작성한 요소에 display: flex가 있는지 확인한다.
  2. 정렬할 item이 그 요소의 바로 아래 자식인지 확인한다.
  3. flex-directionrow인지 column인지 확인한다.
  4. 주축에 실제로 남은 공간이 있는지 확인한다.
  5. item의 flex-grow 또는 margin: auto가 공간을 먼저 사용하고 있는지 확인한다.

Flexbox에서는 auto margin이 정렬보다 먼저 남은 공간을 흡수할 수 있다.

.login-button {
  margin-left: auto;
}

위 코드는 row 방향에서 .login-button을 오른쪽으로 밀 수 있다.
같은 줄에서 justify-content 결과가 예상과 다르다면 item의 auto margin도 살펴봐야 한다.

align-items가 적용되지 않는 원인

align-items도 교차축에 정렬할 공간이 있어야 변화가 보인다.

.container {
  display: flex;
  align-items: center;
}

container 높이가 item 높이와 같다면 세로로 이동할 공간이 없다.
예제를 확인할 때는 heightmin-height로 교차축 공간을 만들어 보면 차이가 선명하다.

.container {
  display: flex;
  min-height: 200px;
  align-items: center;
}

item에 교차축 크기가 명시되어 있으면 stretch 효과가 나타나지 않을 수 있다.

.item {
  height: 80px;
}

또한 text-align: center는 flex item 자체를 가운데로 옮기는 속성이 아니다.
item 안의 inline 콘텐츠를 정렬하는 속성이므로 Flexbox의 축 정렬과 역할이 다르다.

align-self로 하나만 다르게 정렬

align-items는 container의 모든 flex item에 공통 기본값을 준다.
특정 item 하나만 교차축에서 다르게 정렬하려면 align-self를 사용한다.

<div class="container">
  <div class="item">A</div>
  <div class="item featured">B</div>
  <div class="item">C</div>
</div>
.container {
  display: flex;
  align-items: flex-start;
  min-height: 180px;
}

.featured {
  align-self: flex-end;
}

전체 item은 교차축 시작점에 놓이지만 .featured만 끝점에 놓인다.

align-self는 교차축에서 개별 item을 조정한다.
주축에서 item 하나를 따로 밀고 싶다면 상황에 따라 auto margin을 사용하는 방식이 더 직접적이다.

align-content와의 차이

align-itemsalign-content도 이름이 비슷해 자주 혼동된다.

align-items는 한 flex line 안에서 item을 교차축으로 정렬한다.
align-content는 여러 flex line 자체를 교차축에서 정렬한다.

align-content가 동작하려면 item이 여러 줄로 나뉘어야 한다.
따라서 보통 flex-wrap: wrap과 교차축의 남은 공간이 필요하다.

.container {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  width: 320px;
  height: 240px;
}

.item {
  width: 120px;
}

item이 두 줄 이상이 되면 align-content: center가 줄 묶음을 교차축 가운데에 놓는다.
한 줄뿐인 flex container에서는 align-content를 바꿔도 효과가 없다.

정리하면 item 정렬은 align-items, 여러 줄 정렬은 align-content다.

gap으로 item 사이 간격 만들기

정렬 속성은 container의 남은 공간을 배분한다.
item 사이에 항상 일정한 간격을 만들고 싶다면 gap이 더 명확하다.

.actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
}

justify-content: flex-end는 버튼 묶음을 주축 끝으로 보낸다.
gap: 12px은 버튼 사이의 간격을 일정하게 유지한다.

space-between은 남은 container 너비에 따라 간격이 달라진다.
고정된 디자인 간격이 필요하다면 gap, 남은 공간 전체를 분배하려면 space-* 값을 사용하는 편이 자연스럽다.

실전 선택 기준

item이 나열되는 방향에서 정렬하려면 justify-content를 사용한다.

.navigation {
  display: flex;
  justify-content: center;
}

item이 나열되는 방향과 직각인 축에서 정렬하려면 align-items를 사용한다.

.navigation {
  display: flex;
  align-items: center;
  min-height: 64px;
}

가로와 세로 모두 가운데라면 두 속성에 center를 준다.

.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

특정 item 하나만 교차축에서 다르게 놓으려면 align-self를 사용한다.
여러 줄 전체를 교차축에서 정렬하려면 align-content를 사용한다.
item 사이에 고정 간격이 필요하면 gap을 사용한다.

요소를 일반 흐름에서 꺼내 정확한 좌표에 겹쳐야 하는 상황이라면 Flexbox 정렬보다 position이 목적에 맞을 수 있다.
CSS position relative와 absolute 차이에서 그 기준을 확인할 수 있다.

정리

justify-content는 flex container의 주축에서 item을 정렬하고 남은 공간을 배분한다.
align-items는 교차축에서 모든 item의 기본 정렬을 정한다.

기본 row에서는 주축이 가로이고 교차축이 세로다.
column에서는 주축이 세로이고 교차축이 가로다.

두 속성이 적용되지 않는다면 display: flex, flex-direction, 남은 공간, container 크기, item의 flex-grow와 auto margin을 순서대로 확인하면 된다.

가장 중요한 기준은 속성 이름을 가로와 세로로 외우지 않는 것이다.
item이 흐르는 주축은 justify-content, 그와 직각인 교차축은 align-items가 담당한다.

참고 자료

관련 포스트
CSS 가상 클래스와 가상 요소 차이 thumbnail
CSS 가상 클래스와 가상 요소 차이
CSS 가상 클래스와 가상 요소의 선택 대상, 콜론 문법, 상태와 생성 콘텐츠 예제, 접근성 주의점을 정리합니다.
CSS px em rem 차이 thumbnail
CSS px em rem 차이
CSS px, em, rem의 기준값과 중첩 계산 방식, 글꼴 크기와 컴포넌트 간격에 단위를 선택하는 기준을 정리합니다.
CSS display none과 visibility hidden 차이 thumbnail
CSS display none과 visibility hidden 차이
CSS display none과 visibility hidden의 차이를 레이아웃 공간, 포커스, 접근성, 자식 요소, opacity와의 차이로 정리합니다.
CSS position sticky와 fixed 차이 thumbnail
CSS position sticky와 fixed 차이
CSS position sticky와 fixed의 차이를 스크롤 기준, 문서 흐름, 부모 영역, top과 overflow, 고정 헤더 구현 기준으로 정리합니다.
CSS box-sizing content-box와 border-box 차이 thumbnail
CSS box-sizing content-box와 border-box 차이
CSS box-sizing의 content-box와 border-box 차이를 width 계산식, padding과 border, width 100% overflow, 전역 설정 방법으로 정리합니다.
CSS margin과 padding 차이 thumbnail
CSS margin과 padding 차이
CSS margin과 padding의 차이를 박스 모델, 배경색과 클릭 영역, 전체 크기, margin collapsing, 축약형 작성 순서로 정리합니다.
CSS display block inline inline-block 차이 thumbnail
CSS display block inline inline-block 차이
CSS display의 block, inline, inline-block 차이를 줄바꿈, width와 height, margin 동작, 버튼과 태그 UI 선택 기준으로 정리합니다.
CSS position relative와 absolute 차이 thumbnail
CSS position relative와 absolute 차이
CSS position의 기본값, relative와 absolute의 배치 기준, normal flow 유지 여부, containing block, 부모에 position relative를 주는 이유를 초보자 기준으로 정리합니다.
CSS Flexbox와 Grid 차이 thumbnail
CSS Flexbox와 Grid 차이
CSS Flexbox와 Grid의 차이를 1차원과 2차원이라는 기준으로 정리합니다. 줄 바꿈된 Flexbox가 여전히 1차원인 이유와 목록, 카드, 혼합 레이아웃의 선택 기준도 함께 살펴봅니다.
CSS로 글래스모피즘 구현하기 thumbnail
CSS로 글래스모피즘 구현하기
안녕하세요. 오늘은 CSS로 글래스모피즘 디자인을 구현하는 법을 알아보겠습니다. 개인적으로 애플의 디자인 스타일을 좋아해서 좋은 레퍼런스 소재로 구경을 하는데, 오늘 문득 궁금해진 것이 CSS로 어떻게 글래스모피즘을 구현했느냐였습니다.