Flex를 이용한 반응형 레이아웃 만들기

Flex는 레이아웃을 만들 때 아주 유연하고 동적인 구조를 유지할 수 있는 CSS입니다.
유연한 레이아웃을 유지하는 Flex의 속성을 잘 활용하면 미디어쿼리 없이도 웹브라우저 너비와 다양한 디바이스에 대응하는 반응형 레이아웃을 만들 수 있습니다.
미디어쿼리를 이용한 CSS 속성 재정의보다 적은 CSS 작성으로 반응형 레이아웃을 만들 수 있기 때문에, 코드 유지보수 또한 더 단순하고 효율적으로 할 수 있습니다.

레이아웃을 만드는 Flex 속성들

Flex는 다음 6개의 속성을 사용해서 만듭니다.

속성 대상 기본값 설명
flex-wrap Flex 컨테이너 nowrap "wrap", "nowrap", "wrap-reverse" 사용 가능.
Flex 아이템을 배치하는 방법을 선택합니다.
wrap : 인라인으로 아이템을 가로로 배치하며, 행 안에 아이템이 다 차면 다음 행으로 아이템이 이동합니다.
flex-direction Flex 컨테이너 row "row"는 가로 방향(왼쪽 위 에서 오른쪽으로), "column"은 세로 방향(왼쪽 위에서 아래로) 으로 아이템들을 배치합니다.
가로 방향은 속성 설정에 따라 여러 줄로 표현이 가능하며, 세로 방향은 세로로 1줄 표현만 가능합니다.
반대 방향으로 아이템을 배치할 수 있는 반대 방향 속성 값도 제공됩니다.
"row-reverse"는 오른쪽 아래에서 왼쪽으로(그리고 위로 행이 추가됨), "column-reverse"는 왼쪽 아래에서 위로 아이템이 배치됩니다.
gap Flex 컨테이너 0 Flex 아이템 사이의 여백을 지정합니다.
"gap: 열여백 행여백;" 으로 표현하며, 값이 같으면 "gap: 여백;" 으로 사용 가능합니다.
속성을 나누어서 "gap-row", "gap-column" 2개로 행과 열의 사이 여백을 각각 정의할 수 있습니다.
flex-basis Flex 아이템 auto auto, 또는 숫자 단위 너비 값 사용 가능.
Flex 아이템의 기본 크기를 설정합니다. flex-grow, flex-shrink 속성 값이 미지정인 경우, 기본 크기로 고정됩니다.
flex-grow Flex 아이템 0 기본 크기(flex-basis)를 기준으로 한 행에 Flex 아이템 들을 배치한 후, 남는 공간을 아이템들에 분배하는 비율. 비율만큼 아이템이 늘어남. 소수점 사용 가능.
flex-shrink Flex 아이템 1 한 행에 배치된 Flex 아이템 들이 Flex 영역을 넘을 경우, 모자라는 공간만큼 아이템들을 줄이는 비율입니다.
비율에 비례해서 아이템이 너비가 줄어들며 소수점도 사용 가능합니다.
Flex 속성으로 "flex-wrap: wrap;" 이 적용되면 이 속성은 무시됩니다.

Flex 기본 구조

Flex CSS는 다음처럼 기본 구조를 가지는 것이 일반적입니다.
다음의 기본 CSS 구조를 기초로 속성 값을 적절히 조절해서 레이아웃을 변경하게 됩니다.

.flexbox{
  display: flex;
  flex-wrap: wrap;
  gap: 1em;
}
.item{
  min-height: 100px;
  flex-basis: 150px;
  flex-grow: 1; // 레이아웃이 flex-basis 보다 크지면 자동으로 크기가 늘어난다.
}

See the Pen flex : layout-sample1 by younghyeong ryu (@wangta69) on CodePen.

"flex-basis" 속성에서 정한 기본 아이템 너비를 기준으로 남는 여백을 자동으로 채우면서 아이템들을 다음 행에 채워나갑니다.
레이아웃 width 보다 flex-basis 의 합이 작으면 자동으로 채워나가고 크면 한 행에 3개, 또는 2개의 아이템이 자동으로 배치됩니다. 레이아웃 width 여백을 메꾸는 것은 "flex-grow" 속성이 0보다 큰 값으로 지정되어 있기 때문입니다.
"flex-basis" 속성 값으로 정한 너비 이상으로 아이템이 늘어나지 않도록 하려면 다음처럼 Flex 아이템들에 "flex-grow: 0;" 으로 속성을 설정해야 합니다.

.flexbox{
  display: flex;
  flex-wrap: wrap;
  gap: 1em;
}

.item{
  min-height: 100px;
  flex-basis: 150px;
  flex-grow: 0; // 레이아웃이 flex-basis 보다 작더라도  자동으로 크기가 늘어나지 않는다.
}

See the Pen flex : layout-sample2 by younghyeong ryu (@wangta69) on CodePen.

한줄로 표현하는 레이아웃

아이템들의 너비 합이 레이아웃 너비보다 넓으면 여러 행에 나누어져 아이템이 배치되도록 해주는 속성은 "flex-wrap: wrap;" 속성입니다.
이 속성이 없으면 Flex 안의 아이템들은 다음처럼 한 행에 모두 표시됩니다.
그리고 아이템들의 너비 합이 Flex 너비보다 넓으면 다음처럼 레이아웃 영역을 넘지 않도록 아이템들의 너비가 같은 비율로 줄어들면서 한 행으로 레이아웃 안에 배치됩니다. 이것은 "flex-shrink" 속성의 기본 값이 "1"이어서 "flex-shrink" 속성을 정의하지 않아도 기본 값 "1"이 적용되기 때문입니다.

.flexbox{
  display: flex;
  gap: 1em;
  /* flex-wrap: wrap; */ // flex-wrap 이 존재 하지 않으면 자동으로 아래로 떨구어 지지 않는다.
}
.item{
  min-height: 100px;
  flex-basis: 150px;
  flex-grow: 1;
}

See the Pen flex : layout-sample7 by younghyeong ryu (@wangta69) on CodePen.

.flexbox{
  display: flex;
  gap: 1em;
}
.item{
  min-height: 100px;
  flex-basis: 150px;
  flex-grow: 1;
  flex-shrink: 0; // (default: 1) flex-shrink 가 0 이면  flex-basis 보다 레이아웃이 작아도 더 이상 줄어들지 않는다.
}

See the Pen flex : layout-sample7 by younghyeong ryu (@wangta69) on CodePen.

"flex-shrink: 0;" 속성을 적용하면 "flex-basis" 속성의 원래 크기대로 아이템 너비가 설정됩니다.

고정 너비 아이템이 있는 레이아웃

Flex로 레이아웃을 만들다 보면 특정 아이템은 너비를 고정 크기로 지정해서 늘어나거나 줄어들지 않도록 하고 싶을 때가 있습니다. 다음처럼 고정된 너비의 사이드바(<aside>)와 컨텐츠 영역(<article>)으로 나누어진 Flex가 있고, 컨텐츠 영역 안에는 다시 Flex로 배치한 아이템들이 있는 레이아웃을 만들 때, 레이아웃 너비가 변해도 사이드바의 너비는 고정 크기를 가지도록 해보겠습니다.

레이아웃 너비가 "800px"로 제한되어 있고, 사이드바(<aside>)는 "160px" 로 고정합니다. "flex-grow", "flex-shrink" 속성 값을 모두 0으로 지정하면 Flex의 아이템 너비가 변경되지 않고 "flex-basis" 속성으로 지정한 크기로 고정됩니다.

See the Pen flex : layout-sample2 by younghyeong ryu (@wangta69) on CodePen.

Flex CSS가 적용된 레이아웃은 다음처럼 사이드바가 고정된 채로 레이아웃 너비가 변하면서 컨텐츠 영역 안의 Flex 아이템들 배치가 변경됩니다.

사이드바가 고정된 Flex 레이아웃

컨텐츠 내용에 맞춰 자동 크기 조절하기

Flex 아이템의 기본 크기를 결정하는 "flex-basis" 속성 값 중에는 "auto" 속성 값이 있습니다.

자동으로 아이템 너비를 맞춰준다는 뜻이고, 너비를 맞추는 기준은 아이템 안에 들어있는 컨텐츠 내용에 따라 결정됩니다. 다음처럼 아이템에 "auto" 속성 값으로 자동으로 너비가 결정되도록 변경합니다.

.flexbox .item{
    flex-basis: auto;
    background-color: #ffe;
}

아이템 안에 들어있는 컨텐츠가 동일하면 기존에 너비 값을 정한 것과 동일하게 다음처럼 아이템들이 배치됩니다.

두 번째 아이템에 긴 텍스트 내용을 입력하면 처음과는 전혀 다르게 컨텐츠 길이에 맞춰 아이템들이 재 배치됩니다.

See the Pen flex : layout-sample3 by younghyeong ryu (@wangta69) on CodePen.

미디어쿼리와 함께 반응형 지원하기

미디어쿼리와 함께 Flex를 사용하면 반응형 레이아웃을 빠르고 간편하게 만들 수 있습니다.

특히, 아이템 사이의 여백 처리와 한 행당 표시하는 아이템 갯수를 빠르게 정의할 수 있습니다.

자동으로 아이템이 배치되도록 할 때, 특정 아이템 한개만 한 행에 위치하면서 너비가 Flex 너비로 커지는 것은 같은 종류의 아이템(예를 들면 사진이나, 쇼핑몰 상품 목록 처럼)을 목록으로 나열하는 경우 문제가 됩니다.

데스크탑 화면에서는 한 행에 4개, 타블렛에서는 한 행에 2개, 모바일에서는 한 행에 1개의 아이템이 표시되도록 미디어쿼리와 Flex 속성을 사용해 CSS를 만들어 보겠습니다.

먼저 반응형 레이아웃을 만들때 아이템 크기를 "%" 단위로 정의할 것이므로(한 행에 위치시킬 갯수를 이미 알고 있으므로) 아이템 사이의 여백(갭)도 다음처럼 "%" 단위로 변경해야 합니다.

.flexbox{
    display: flex;
    flex-wrap: wrap;
    gap: 2%;
}

이제 미디어쿼리를 이용해 가로 너비를 기준으로 아이템 갯수가 고정되도록 Flex 속성을 정의합니다.

See the Pen flex : layout-sample2 by younghyeong ryu (@wangta69) on CodePen.

간단하지만, 결과는 다음처럼 너비에 따라 표시되는 아이템 갯수가 정확하게 나누어집니다.

미디어쿼리와 조합해서 Flex를 정의하면 중간의 불필요하게 아이템이 나누어지면서 행별로 아이템 갯수가 다른 경우가 발생하지 않도록 처리를 할 수 있습니다.

미디어쿼리 없이 모바일 대응하기

CSS 숫자 연산 결과를 얻는 calc() 메서드를 활용하면 모바일 기기에 대한 대응을 미디어쿼리 없이 할 수 있습니다.

미디어쿼리를 완전히 대체하는 것은 아니며, 레이아웃 구조가 단순해서 여러가지 너비에 대한 대응을 할 필요가 없거나, 조금이라도 더 빠르고 간결한 CSS 유지를 위한 트릭의 한가지 입니다.

모바일 기기 지원을 위한 레이아웃 너비를 "768px"로 하기로 하고, 그 보다 너비가 작은 레이아웃 화면(웹브라우저 너비) 에서는 Flex 아이템 배치를 모바일 대응으로 하도록 하려면 다음과 같이 아이템의 너비를 정해줍니다.

See the Pen flex : layout-sample5 by younghyeong ryu (@wangta69) on CodePen.

중요한 것은 아이템 기본 너비를 결정하는 속성인 "flex-basis" 에 적용한 속성 값인 "calc(calc(768px - 100%) * 1000000)" 계산식입니다.

계산식의 "100%"는 Flex의 현재 너비 값이 적용됩니다. 중요합니다. "1000000" 는 아주 큰 숫자를 곱하기 위해 정한 임의의 숫자이며, 특별한 의미가 있는 것은 아닙니다.

참고로, 구글 크롬의 경우, 소수점 픽셀 계산 값이 그대로 화면 렌더링시 적용되며, 소수점 둘 째 자리까지는 일반적으로 표기됩니다. 이런 소수점 픽셀 계산 결과 값이 작은 계산 결과 값으로 인해 계산 착오가 생기는 것을 막기 위해 큰 숫자를 곱하는 것입니다.

경험적으로 "1000000" 이상이면 고해상도 모니터 너비에도 문제없이 대응이 되기 때문에 "1000000"으로 정한 것입니다.

계산식의 결과는 2가지로 나누어집니다.

Flex 너비가 "768px" 보다 크거나 같으면 calc() 메서드 계산 결과는 0보다 작거나 같은 숫자가 되고, "flex-basis" 속성 값은 무시되며, 기본 값인 "auto" 가 됩니다. "flex-basis" 속성 값에서 음수 값은 무시됩니다. Flex 너비가 "768px" 보다 작으면 무한히 큰 숫자가 됩니다. 실제로 무한히 큰 것은 아니고 내부 calc() 메서드 결과 값에 1000000 을 곱했으므로 일반적으로 사용하는 웹 레이아웃 너비인 1000px ~ 1600px 너비보다는 훨씬 큰 값이 되기 때문에 레이아웃 용으로는 충분히 큰 크기가 됩니다. 따라서 Flex의 "768px" 너비를 기준으로 다음처럼 레이아웃이 반응형으로 동작하게 됩니다.

평점을 남겨주세요
평점 : 2.5
총 투표수 : 1