본문 바로가기
이론/Frontend

CSS 레이아웃 배치하기 - Flex

by 유세지 2022. 4. 20.

레이아웃을 잡는 Flex와 Grid

Flex와 Grid는 레이아웃을 배치할때 사용하는 대표적인 css 속성입니다. 기존의 float나 absolute, inline-block 등의 속성들을 조합하여 사용하는 방법보다 훨씬 간편하게 원하는 레이아웃을 만들 수 있는 장점이 있어 널리 사용되고 있습니다. Flex는 개인적으로도 많이 사용했었지만 아직까지도 정확히 어떻게 활용해야 원하는 레이아웃을 만들 수 있는지 모르고, 그때그때 되는 식으로 주먹구구로 적용하고 있어 이번 기회에 Grid까지 함께 공부해보려고 합니다.

Flex

먼저 Flex입니다. Flex, 또는 Flexbox라고 불리는 이 속성은 요소의 크기가 정해지지 않았거나 동적으로 변할때 효율적으로 레이아웃을 구성할 수 있는 방법을 제공합니다. Flexbox는 크게 부모자식, 두 가지로 구성됩니다.

 

여기서 부모는 flex container, 즉 컨테이너라고 부르고

자식은 flex item, 즉 아이템이라고 부릅니다.

 

부모가 될 요소에 display: flex; 속성을 할당하는 것으로 간단히 flex를 적용할 수 있습니다.

 

 

Flex container의 정렬 방향 결정하기

Flex container의 정렬 방향은 기본적으로 가로 방향(행: row)으로 설정됩니다. 이는 Flex item들이 왼쪽에서 오른쪽으로 정렬되는 것을 의미하며 flex-direction 속성을 이용해 변경할 수 있습니다.

 

flex-direction: row; // 가로(행) 방향 정렬
flex-direction: column; // 세로(열) 방향 정렬

 

또한, direction 속성에 reverse를 추가하여 역방향 정렬도 구현할 수 있습니다.

 

flex-direction: row-reverse; // 가로 역방향 정렬 (오른쪽 -> 왼쪽)
flex-direction: column-reverse; // 세로 역방향 정렬 (아래쪽 -> 위쪽)

 

 

Flex item의 정렬 방향 결정하기

이번에는 flex item들의 정렬 방향을 결정해보겠습니다. item은 두 가지 측면에서 정렬할 수 있습니다.

첫 번째는 justify-content를 사용해 컨테이너의 정렬 방향을 기준으로 하는 방법입니다.

 

justify-content

justify-content: flex-start; // 시작 부분부터 정렬
justify-content: center; // 중간부터 정렬
justify-content: flex-end; //  끝 부분부터 정렬
justify-content: space-between; //  처음과 끝 부분은 양 끝에 고정, 이후 같은 간격으로 정렬
justify-content: space-around; // 모든 요소가 동일한 margin 값을 갖도록 고정 (실제 margin이 아닙니다!)

 

컨테이너의 정렬 방향을 기준으로 적용되기에, row라면 가로줄을 기준으로 정렬되고 column이라면 세로줄을 기준으로 정렬됩니다. flex direction의 값이 row라고 가정해보겠습니다.

 

flex-start는 컨테이너의 시작 부분부터 정렬됩니다. row이므로 왼쪽부터 차례대로 쌓이게되며, justify-content의 값을 따로 설정하지 않으면 기본값으로 할당됩니다.

 

flex-end는 마찬가지로 컨테이너의 끝 부분부터 정렬됩니다. 오른쪽부터 차례대로 쌓이게됩니다.

 

center는 이름처럼 컨테이너의 중앙부분에 정렬됩니다. 아이템들의 집합과 양쪽 끝까지의 거리가 같은 가운데 정렬이라고 생각하시면 됩니다.

 

space-between은 요소가 처음과 끝 부분에 고정되는 양쪽 정렬입니다. 아이템이 두 개면 양 쪽 끝에 배치되고, 세 개부터는 양 쪽 끝과 가운데에 배치되기 시작해 모든 아이템이 같은 간격을 갖게됩니다. 만약 아이템이 하나라면 컨테이너의 시작 부분에 위치하게 됩니다. (row라면 왼쪽, row-reverse라면 오른쪽)

 

space-around는 모든 요소가 같은 margin 값을 갖는 정렬입니다. 요소와 요소끼리는 물론이고, 컨테이너와도 동일한 margin을 유지하게 됩니다. 예를 들어 맨 끝에 배치된 아이템이 5px의 margin을 갖는다고 하면 그 아이템과 컨테이너 사이의 거리는 5px가 될 것이고, 그 아이템과 인접한 아이템과의 거리는 아이템의 margin인 5px에 인접한 아이템의 margin인 5px를 더해 10px가 될 것입니다.

 

 

 

* 이해를 돕기 위해 유사한 동작을 보이는 margin이라는 표현을 사용했는데, 실제로 margin이 적용되는 것은 아니니 이 점 유의해주세요!

 

 

두 번째 방법은 align-items 를 사용해 컨테이너의 정렬 방향에 수직인 축을 기준으로 하는 방법입니다.

 

align-items

align-items: stretch; // 기본값, 늘려서 컨테이너에 맞추기
align-items: flex-start; // 시작 부분부터 정렬
align-items: center; // 중간 부분에서 정렬
align-items: flex-end; // 끝 부분부터 정렬
align-items: baseline; // baseline에 맞춰서 정렬

 

위와 마찬가지로 컨테이너의 정렬 방향은 기본값인 row라고 생각하겠습니다.

 

stretch는 아이템의 길이를 늘려서 수직 공간을 모두 채웁니다. 컨테이너의 정렬 방향이 row이므로 아이템이 세로축을 가득 채우게 됩니다. 따로 값을 지정하지 않으면 기본값으로 할당되는 속성입니다.

 

flex-start는 아이템을 시작 부분(위)에서부터 정렬합니다. 모든 아이템이 상단에 딱 붙어있는 형태가 됩니다.

 

center는 아이템을 중앙에서부터 정렬합니다. 모든 아이템의 중앙 부분이 일자로 쭉 연결되는 형태가 됩니다.

 

flex-end는 아이템을 끝 부분(아래)에서부터 정렬합니다. 모든 아이템이 하단에 딱 붙어있는 형태가 됩니다.

 

baseline은 아이템을 요소의 baseline에 맞춰서 정렬합니다. 텍스트에서 흔히 보이는 속성인 baseline에 맞춰서 정렬하기에 요소의 내부에 텍스트가 들어갈때 유용하게 사용할 수 있습니다.

 

 

align-items는 훌륭하지만, 사실 이것만으로는 수직 축을 정렬하기에 충분하지 않습니다. 아이템들이 많아져 두 줄 이상이 되면 이 아이템들 자체를 정렬할 필요도 생기기 때문입니다. 컨테이너보단 하위이고, 아이템보다는 상위인... 아이템 레퍼라고 할까요? 레퍼를 정렬하기 위해 사용하는 align-content가 있습니다.

 

align-content

align-content를 이용하면 아이템들의 레퍼를 컨테이너의 정렬 방향에 수직인 방향으로 정렬할 수 있습니다. 여러 행으로 구성된 아이템들을 정렬하는 속성이므로, flex-wrapwrap으로 설정 되어있어야 기대했던 결과를 받을 수 있습니다. (flex-wrap의 기본값은 nowrap입니다.)

 

flex-wrap: wrap; // 정상적인 동작을 위해 설정해줍시다.

align-content: stretch; // 기본값, 아이템의 길이를 늘려서 맞추기.
align-content: flex-start; // 아이템 레퍼를 정렬의 시작 부분부터 정렬.
align-content: center; // 아이템 레퍼를 정렬의 중간 부분부터 정렬.
align-content: flex-end; // 아이템 레퍼를 정렬의 끝 부분부터 정렬.
align-content: space-between; // 아이템들의 양 끝 줄을 고정시킨 뒤 같은 길이로 정렬.
align-content: space-around; // 아이템들을 같은 길이의 margin을 같도록 정렬.

 

기본적으로 위에서 살펴 본 justify-content의 속성들과 유사한 동작을 보입니다. 마찬가지로 flex-direction이 row라고 가정하겠습니다.

 

stretch는 아이템의 길이를 늘려 컨테이너에 꽉 차게 맞춥니다. align-content를 따로 지정하지 않으면 기본으로 적용됩니다.

 

flex-start는 아이템 레퍼를 정렬의 시작 부분부터 정렬합니다. 레퍼가 상단에 붙어있는 느낌이라고 생각하시면 좋습니다.

 

center는 아이템 레퍼를 정렬의 중간 부분부터 정렬합니다. 레퍼가 중단에 붙어있는 느낌이라고 생각하시면 좋습니다.

 

flex-end는 아이템 레퍼를 정렬의 끝 부분부터 정렬합니다. 레퍼가 하단에 붙어있는 느낌이라고 생각하시면 좋습니다.

 

space-between은 아이템 레퍼 내부의 첫 라인과 마지막 라인을 양 끝에 정렬합니다. 그리고 남은 라인들은 균등한 간격으로 배치합니다. 양 끝 정렬이라고 생각하시면 좋습니다.

 

space-around는 위에서 설명 한 것처럼 아이템들이 같은 길이의 margin을 갖는다고 생각하시면 이해하기 편하실겁니다.

 

 

Flex item에 속성 부여하기

이번에는 Flex item에 속성을 부여해보겠습니다. Flex는 간편한 정렬 외에도, 각 요소에 자세한 옵션을 설정해 다양한 스타일을 줄 수 있습니다. 대표적으로 사용되는 세 가지 속성을 살펴보겠습니다.

 

flex-basis

먼저 아이템의 기본 크기를 설정해주는 flex-basis입니다. 

컨테이너의 정렬 방향에 따라 아이템이 가져야하는 최소한의 크기를 설정해주는 옵션인데, flex-direction이 row일 경우 min-width를, flex-direction이 column일 경우 min-height를 의미한다고 생각하셔도 좋습니다.

 

flex-basis: auto; // 기본값, 아이템의 기본 길이를 사용
flex-basis: 100px | 100% | 10rem; // 특정 값으로 지정
flex-basis: content; // 콘텐츠의 길이를 사용

 

auto는 아이템의 기본 길이를 그대로 사용합니다. 따로 설정하지 않으면 기본값으로 갖는 길이로 정해집니다.

 

또는 특정 값으로 정해줄 수도 있습니다. px 단위, % 단위, rem(또는 em) 단위 모두 사용 가능 합니다.

 

content는 콘텐츠의 길이를 그대로 사용합니다. 아이템의 기본 길이를 갖는 auto와 혼동하기 쉬운 개념이지만, 두 값은 다를 수 있습니다. 원래 요소의 길이는 100px이지만, 사전에 아이템의 길이를 150px로 설정해 준 요소가 있다고 가정해보겠습니다. 이때 auto를 사용하면 사전에 설정한 150px로 맞춰지지는데 반해, content를 사용하면 사전 설정을 무시하고 100px로 맞춰지게 됩니다.

 

 

 

flex-grow

다음은 아이템의 크기를 늘릴 수 있도록 조정해주는 flex-grow 입니다. flex-grow 속성의 기본값은 0인데, 이는 현재 flex-grow를 사용하지 않겠다는 것을 의미합니다. 여기에 0보다 큰 값을 주는 것으로 활성화시킬 수 있고, 이때 지정한 비율에 따라 각 요소들이 남은 공간들을 나눠 갖게됩니다.

 

flex-grow: 0; // 기본값, flex-grow 사용하지 않음
flex-grow: 1; // flex-grow 사용, 각각의 자식 요소가 1의 비율로 나눠가짐

 

따라서 모든 자식 요소에 기본적으로 flex-grow: 1을 할당하고, 일부 자식 요소에만 2를 할당해준다면 그 자식 요소는 다른 요소에 비해 남은 공간을 두 배로 가져가게 됩니다.

 

 

flex-shrink

마지막으로 아이템의 크기를 줄일 수 있도록 조정해주는 flex-shrink 입니다. flex-grow와 반대로 기본값이 1인데, 따로 값을 지정하지 않으면 항상 활성화 되어있는 상태입니다. 따라서 별다른 처리 없이도 위의 flex-basis에서 지정해 준 값보다 작아질 수 있고, flex-shrink 값을 0으로 주어 비활성화 시켜주면 작아지지 않게 만들 수도 있습니다.

 

flex-shrink: 1; // 기본값, 활성화 상태이며 flex-basis의 값보다 작아질 수 있음
flex-shrink: 0; // 비활성화 상태이며 flex-basis의 값보다 작아질 수 없음

 

 

flex

flex 축약형을 이용하면 위 세 가지 속성을 한 번에 할당해 줄 수 있습니다.

 

/* 값이 세 개일때, flex: flex-grow | flex-shrink | flex-basis */
flex: 1 0 auto; // flex-grow: 1, flex-shrink: 0, flex-basis: auto

/* 값이 두 개일때, flex: flex-grow | (flex-shrink 또는 flex-basis) */
flex: 1 0; // flex-grow: 1, flex-shrink: 0
flex: 1 auto; // flex-grow: 1, flex-basis: auto

/* 값이 한 개일때, flex: flex-grow 또는 flex basis */
flex: 1; // flex-grow: 1
flex: 50%; // flex-basis: 50%

 

지정해주는 순서에 따라, 속성의 타입에 따라 어떤 속성에 값을 할당할지가 달라지기 때문에 주의하여 할당해야 합니다. 자세한 정보는 MDN 문서를 참고하시면 좋습니다.

 

마무리

여기까지 Flex에 대해 알아보았습니다. 다음 포스팅에서는 Grid에 대해 알아보겠습니다.

 

참고 문서

flexbox로 만들 수 있는 10가지 레이아웃 - 네이버 D2

이번에야말로 CSS Flex를 익혀보자 - 1분 코딩

Flex - MDN Web Docs

댓글