CSS

[CSS] flex-basis, flex-shrink, flex-grow 활용 -2

맨날개발 2025. 7. 16. 23:00

🔗 이전 내용

flex-basis 알아보기 - 1
flex-shrink, flex-grow 알아보기 - 2

 

📢 flex 단축 속성

flex-basis, flex-shrink, flex-grow는 개별 속성으로 사용될 수 있지만 단축 속성인 flex를 사용하는 경우도 많다.

몇개의 값을 사용할 지, 단위는 무엇으로 할 지에 따라 설정되는 속성이 달라진다.

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    div {
      display: flex;
    }

    span {
      flex: 1;
    }
  </style>
</head>
<body>
  <div>
    <span></span>
  </div>
</body>
</html>

 

위의 코드와 같이 span에 flex 속성으로 단일 값 1을 설정하였다. 이 경우 flex-grow에 값이 할당된다.

 

개발자 도구를 통해 아래와 같이 단축 속성에 설정 된 값이 어떤 속성에 할당되는지를 확인할 수 있다.(화살표를 클릭)

 

다음과 같은 규칙에 따라 설정된다.

 

  1. 단위를 작성하지 않은 경우
    • 한개의 값 : flex-grow 에 적용
    • 두개의 값 : flex-grow, flex-shrink 순으로 적용
    • 세개의 값 : flex-basis에서는 단위없이 숫자만으로 값 할당이 불가능하기 때문에 값 할당 불가
  2. 단위를 작성하는 경우
    • 한개의 값 : flex-basis 에 적용 (나머지는 1)
    • 두 개 이상의 값 : 단위를 작성할 수 있는 경우는 flex-basis 하나이기 때문에 값 할당 불가
  3. 혼합
    • 두개의 값 : 단위가 존재하는 값은 flex-basis에, 단위가 없는 숫자는 flex-grow에 할당(나머지는 불가)
    • 세 개의 값 : 단위가 존재하는 값은 flex-basis에 단위가 존재하지 않는 나머지 숫자는  순서대로 flex-grow, flex-shrink에 할당. 이때 flex-basis 값은 처음과 마지막에만 올 수 있다.
flex: 2; // flex-grow 에 2
flex: 10px; // flex-basis에 10px
flex: 10px 2; // flex-basis에 10px, flex-grow에 2
flex: 2 10px; // flex-grow에 2, flex-basis에 10px
flex: 10 5; // flex-grow에 10, flex-shrink에 5
flex: 10 5 10px; // flex-grow에 10, flex-shrink에 5, flex-basis에 10px
flex: 10px 5 10; // flex-basis에 10px, flex-grow에 10, flex-shrink에 5

 

✨ 할당되지 않은 경우 flex-grow와 flex-shrink는 1로 초기화, flex-basis는 0%으로 초기화 된다.

 

 

🎲 사용해보기

플렉스박스와 justify-content, align-items 만 활용해도 레이아웃을 손쉽게 구성할 수 있다. flex-basis, flex-grow, flex-shrink를 활용하면 좀더 다채롭게 화면을 구성할 수 있다.

 

 

1️⃣ 남은 공간을 하나의 요소에 몰아주기

아래는 flex를 사용하는 가장 간단한 예제이다.

 

컨테이너 영역에 input과 버튼이 존재한다. 컨테이너 영역의 남은 여백은 모두 input의 사이즈로 설정하려고 한다. 다음과 같이 flex: 1을 활용하였다.

See the Pen Untitled by suld2495 (@suld2495) on CodePen.

 

flex: 1로 설정하게 되면 다음과 같이 속성이 적용된다.

flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%;

 

지난 포스트에서 요소에 값이 설정되는 순서를 따라가보면 결과가 어떻게 나올지 이해할 수 있다.

  1. flex-basis가 우선 적용. 너비가 0%로 설정된다. 현재 min-width가 0이기 때문에 0으로 설정된다.
  2. 남은 여백이 존재하기 때문에 남은 여백을 input이 모두 차지한다. 왜냐하면 flex-grow의 기본값은 0이기 때문에 button은 여백을 할당받지 못한다.
  3. 컨테이너를 초과하지 않기 때문에 여기서는 flex-shrink가 작동하지 않는다.

flex: 1만 추가해서 간단하게 완료가 되었다.

 

 

현재는 input에 min-width를 0으로 설정하여 지금과 같이 간단하게 설정이 될 수 있었으나, 만약 input에 min-width가 없다면 예상치 못한 결과가 나오게 된다.

See the Pen Untitled by suld2495 (@suld2495) on CodePen.

 

위와 같이 버튼이 한글자식 줄바꿈이 되는 이유는 input에 min-width가 설정되어 있고 더 이상 줄어들지 않기 때문에 컨테이너를 초과하게 되었다. flex-shrink의 기본값은 1이기 때문에 input과 button 모두 동일한 비율로 초과분에 대해서 사이즈가 줄어들게 된다.

 

위와 같은 문제는 퍼블리싱을 하다보면 종종 만나게 되는 이슈이다. 

 

우리가 원하는 결과는 button의 사이즈는 자신의 컨텐츠를 그대로 유지하고 남은 여백만 input의 사이즈가 되기를 원한다. 아래와 같이 flex-shrink를 설정하여 초과영역에 대해서 사이즈를 줄이지 않도록 설정할 수 있다.

button {
  flex-shrink: 0;
}

See the Pen Untitled by suld2495 (@suld2495) on CodePen.

위의 경우에는 input에 min-width가 설정되어 있어, flex-shrink만 설정하는 경우 컨테이너를 넘어서게 된다. 위와 같은 경우라면 input에 min-width도 설정해주자!

 

 

2️⃣ 플레스 아이템에 스크롤 추가하기

아래의 예제는 컨테이너 영역 내부에 리스트와 버튼이 존재한다.

 

요구 조건은 다음과 같다.

  1. 리스트 영역은 데이터에 사이즈에 따라, 컨테이너 영역보다 커지는 경우 스크롤이 생겨야 한다.
  2. 리스트 영역은 배경컬러가 적용되어 있기 때문에 버튼을 제외하고 컨테이너의 남은 영역을 모두 차지해야 한다.

2번의 조건을 충족시키기 위해 flex: 1을 사용하였다. 요구사항에 맞게 간단하게 적용하였다.

See the Pen Untitled by suld2495 (@suld2495) on CodePen.

 

위 코드 보다 좀 더 복잡한 구조로 연습해보자. 변경사항은 다음과 같다.

  1. 기존 레이아웃에서 div로 한번 더 감싸준다,
  2. 새롭게 생성한 div의 높이를 200px로 설정한다.
  3. 바로 하위에 h1 요소를 추가한다.
  4. 기존 div의 높이 100px를 제거 하고 h1 요소의 사이즈를 제외한 나머지 여백을 차지하기 위해 flex: 1로 설정한다.
  5. 나머지는 동일하다.

See the Pen Untitled by suld2495 (@suld2495) on CodePen.

 

이제 더 이상 스크롤이 생성되지 않는다.

 

스크롤이 생성되도록 하기에 앞서 먼저 높이를 결정하게 되는 순서부터 알아보자.

  1. #container는 200px로 고정되어 있기 때문에 높이가 200px
  2. h1은 마진까지 포함하여 대략 88px 정도를 컨텐츠 높이로 차지
  3. #list는 flex-grow가 1이고 h1은 flex-grow가 0이기 때문에, #list의 높이는 대략 112px인데 gap을 제외하고 대략 102px
  4. 하지만 #list의 자식 컨텐츠의 높이가 ul이 160px, 버튼이 21px, gap이 10px해서 총 최소 높이가 대략 190px

위 순서로 진행됨에 따라 #list는 대략 190px의 높이를 가지게 된다. 기본적으로 min-height의 기본값은 auto이다.

 

그래서 컨텐츠의 최소 높이가 190px이고, 플렉스 아이템의 shrink가 1 이상으로 설정되어 있더라도 최소 값보다는 작아지지 않기 때문에 최소 높이인 190px로 최종 설정되어 스크롤이 생성되지 않는다.

 

 

그래서 스크롤이 나오도록 하는 방법은 위의 결론에서 추출할 수 있다. 바로 최소값을 0으로 설정하면 된다. 그럼 컨테이너를 초과하는 공간에 대해서 flex-shrink 값에 따라 #list의 높이가 줄어들게 된다.

 

See the Pen Untitled by suld2495 (@suld2495) on CodePen.

 

 

3️⃣ 플렉스박스에서도 text-align이 적용된다.

가끔 플렉스박스에서는 text-align이 적용되지 않는다고 착각하는 경우가 존재한다.

 

다음과 같은 상황으로 예시를 들어보겠다. 너비와 높이가 200px인 박스가 존재한다. 현재는 텍스트만 중앙 정렬되어 있다.

<style>
div {
  width: 200px;
  height: 200px;
  text-align: center;
}
</style>

<div>
  Hello World
</div>

 

 

수직방향으로도 가운데 정렬을 하려고 한다. 플렉스 박스를 활용하면 수직 정렬을 간단하게 할 수 있기 때문에 아래와 같이 스타일을 적용했다.

<style>
div {
  width: 200px;
  height: 200px;
  display: flex;
  align-items: center;
  text-align: center;
}
</style>

<div>
  Hello World
</div>

 

변경 후 결과에서 플렉스박스로 전환하기 전에는 잘 작동하던 text-align이 플렉스박스로 변경하자 왼쪽 정렬이 되어버렸다. 

 

그래서 플렉스박스에서는 text-align이 작동하지 않는다는 결론과 함께 justify-content: center 를 활용해 중앙 정렬을 맞추게 된다.

 

보통 이러한 흐름을 통해서 text-align이 작동하지 않는다는 착각을 하게 된다(작성자 본인 이야기). 이러한 착각을 하게 되는 이유는 바로 플렉스 박스로 전환하게 되면 텍스트 노드는 익명의 블럭 박스가 되고, 이는 플렉스 아이템과 동일하게 렌더링된다.

 

플렉스 아이템이 되었기 때문에 flex-grow가 0 값을 가지게 된다. 즉, 최소사이즈만 가지고 컨테이너에는 여백이 생기게 된다. 텍스트 노드를 감싸는 익명 블럭 박스에 스타일을 적용할 수 없기 때문에 justify-content: center를 통해서만 중앙정렬이 가능하다.

 

justify-content로는 text-align와 같은 텍스트 중앙 정렬을 적용할 수 없다는 것은 다음 결과를 보면 알 수 있다.

아래의 결과를 보면 텍스트가 중앙 정렬된 것이 아닌 익명 블럭박스가 중앙 정렬된 것이다.

See the Pen Untitled by suld2495 (@suld2495) on CodePen.

✨ 두 속성에 대한 차이를 명확하게 구분하자!

 

 

 

🙄 정리

  • min-width/min-height의 초기값은 auto 이기 때문에 자식 컨텐츠에 따라 flex-shrink가 설정되어 있어도 컨테이너를 초과할 수 있다.
  • 자식 컨텐츠의 사이즈는 자식 요소의 너비/높이 + 패딩 + 테두리 + 마진이다.
  • display: flex를 설정해도 text-align이 적용된다. 적용되지 않는 것 같으면 너비를 텍스트보다 크게 늘려보자.