• [CSS] 레이아웃을 더 편하게, Flexbox

    2019. 1. 7.

    by. 나나 (nykim)



    1. Flexbox를 지원하는 브라우저

    Flexbox를 쓰면 훨씬(!) 더 쉽게(!!) 레이아웃을 스타일링할 수 있습니다.

    기존에는 일반적으로 float 속성을 이용했는데, 이건 clearfix라는 핵이 필요했죠.

    그밖에 display:table-cell 등, 원래 이러라고 만든 게 아닐텐데... 하는 속성을 써야 했습니다.


    이제 Flexbox를 쓰면 가운데 정렬이고 뭐고 손쉽게 가능합니다.

    다만 국내에서는 Flexbox가 그렇게 보편적이지 못한데,

    그 이유는 아마 IE에 대한 지원이 영 좋지 못하기 때문인 것 같습니다.

    우선 Flexbox는 IE 10부터 지원합니다. 단, prefix로 -ms-가 필요합니다.

    IE 10과 11에서 몇 가지 버그가 있다고 알려져 있고, 이때문에 사용하기 영 꺼려지는 것도 사실이죠.

    또한 일부 브라우저 버전은 -webkit- 등의 prefix를 필요로 합니다.


    따라서 Flexbox는 모던 브라우저를 대상으로 제작할 때 추천하며,

    prefix를 기본적으로 붙이는 것이 좋습니다.


    참고)

    https://caniuse.com/#search=flex

    https://developer.mozilla.org/ko/docs/Web/CSS/flex


    2
    . Flexbox 모델을 사용하자

    [Property #1] display: flex

    Flexbox 모델을 사용하려면, 부모 요소(=flex container)에게 display:flex 속성을 줍니다.

    그럼 자식 요소(=flex item)들이 자동으로 정렬되는 것을 볼 수 있습니다.

    한편, display: inline-flex를 주면 인라인 레벨의 컨테이너가 생성됩니다.

    이렇게 생성된 flex container는 몇 가지 속성을 사용할 수 없으니 주의가 필요합니다.

    display: flex;
    dispaly: inline-flex;

    01. 『column-*』 , 『float』 , 『clear』 프로퍼티 사용 불가

    02. 『position: abolute』나 『position: fixed』를 쓰면 flex item에서 제외됨

    03. 브라우저마다 구현이 다를 수 있으므로, margin이나 padding으로 %값을 주지 않도록


    한편, flex item의 초기 설정값은 다음과 같습니다.

    flex-derection: row; (가로로 나열)
    flex-basis: auto; (container 너비만큼 수축)
    flex-wrap: nowrap; (개행하지 않음)
    flex-grow: 0; (여분이 있어도 늘어나지 않음)
    flex-shrink: 1; (container 너비가 좁아지면 수축)
    .container {
      display: -webkit-flex;
      display: -moz-flex;
      display: -ms-flex;
      display: -o-flex;
      display: flex;
    }
    .item {
      width: 80px;
      height: 80px;
    }

    display: block; 


    display: flex;



    [Property #2] flex-direction

    display:flex를 하게 되면, 기본적으로 왼쪽 -> 오른쪽 정렬로 flex item이 배열 됩니다.

    그럼 세로로 정렬하려면 어떻게 할까요?

    flex-direction: column을 지정하면 됩니다. flex-direction: row가 default 값이 되겠죠.

    이렇게 가로 또는 세로 정렬을 지정할 때 사용합니다.

    flex-direction에는 다른 속성들도 있습니다

    flex-direction: row-reverseflex-direction: column-reverse인데, 이름에서 보이는 그대로 "거꾸로" 배열시킵니다.

    flex-direction: row;              ⇒ 가로 정렬 [初期値]
    flex-direction: column;           ⇒ 세로 정렬
    flex-direction: row-reverse;      ⇒ 가로로 정렬하되 순서를 역배치
    flex-direction: column-reverse;   ⇒ 세로로 정렬하되 순서를 역배치

    flex-direction: row-reverse;


    flex-direction: column-reverse;


    [Property #3] flex-basis

    flex-basisflex item의 너비를 지정합니다.

    px로 고정 값을 줄 수도 있고, % 값을 주면 flex container의 폭에 맞춰 그 비율만큼 차지합니다.

    이 속성은 flex item에게 지정합니다.

    기본 너비와 높이가 80px인 상태여서, 이걸 flex-basis로 값을 재정의한 모습입니다.

    .item:nth-child(1) {
      flex-basis: 150px;
    }
    .item:nth-child(2) {
      flex-basis: 50%;
    }
    .item:nth-child(3) {
      flex-basis: 110px;
    }


    flex-basis는 width보다 값이 우선하기 때문에, flex-basis값을 명시하는 것이 좋습니다.


    [Property #4] flex-wrap

    flex-wrap을 쓰면, flex container에 들어가지 않는 flex tem을 '그대로 1행으로 표시할지, 아니면 개행할지'를 제어할 수 있습니다.

    기본적으로 flex item은 총합의 너비가 flex container의 너비를 초과하는 경우,

    container 너비에 맞춰 자동으로 축소되며, 그 비율은 flex-basis에 따라 달라집니다.

    값은 다음의 3가지가 있습니다.

    flex-wrap: nowrap;         ⇒ 개행 없음 [初期値]
    flex-wrap: wrap;           ⇒ flex container에 들어가도록 개행해서 표시
    flex-wrap: wrap-reverse;   ⇒ 개행하되 문자 방향을 역으로 표시

    flex-wrap:nowrap;

    flex-wrap:wrap;


    값이 nowrap일 때는 flex item의 크기를 줄여서라도 container의 1행에 모여있지만,

    값이 wrap일 때는 container의 너비가 부족하다면 크기를 줄이지 않고 개행되는 것을 확인할 수 있습니다.


    [Property #5] flex-flow

    flex-flow를 쓰면 flex-direction과 flex-wrap을 동시에 지정할 수 있습니다. 넵, 그게 다에요 :-9

    flex-flow: 【flex-direction의 값】 【flex-wrap의 값】;
    flex-flow: row-reverse wrap;

    [Property #6] flex-grow

    flex-grow는 flex item이 늘어나는 배율을 지정합니다.

    flex container의 여백이 있는 경우, flex-grow로 지정한 값에 따라 자동적으로 늘어나 여백을 메꾸게 됩니다.

    만약 flex-grow를 개별로 지정한 경우, 지정하지 않은 item은 최소치가 됩니다.

    값은 flex item에게 지정하며, 정수(正の数)만 가능하고 음수(負の値)는 불가능합니다.

    .item {
      flex-grow: 1;
    }
    
    .item:nth-child(3) {
      flex-grow: 3;
    }

    container의 너비가 900px이고, item의 각 너비가 80px인 상태


    item 3에게 flex-gorw: 3을, 나머지에게 flex-grow: 1을 준 상태


    예를 들어, container의 너비가 900px이고, item의 각 너비가 80px인 상태라고 합시다.

    3번째 item에게만 flex-grow: 3을, 나머지 item들에게는 flex-grow: 1을 지정했습니다.

    flex-grow 속성을 줬기 때문에 모든 item들은 container의 여백을 채우고자 늘어납니다.

    이때, flex-grow: 3은 다른 item의 3배 배율만큼 늘어납니다.

    .item:nth-child(1) {
      flex-grow: 1;
    }
    .item:nth-child(2) {
      flex-grow: 2;
    }
    .item:nth-child(3) {
      flex-grow: 3;
    }

    item1~3에게만 각각 flex-grow:1~3을 주고, 나머지에게 flex-grow 값을 주지 않은 상태

    이번엔 1~3번째 item에게 각각 flex-grow:1~3을 주고, 나머지에게는 flex-grow를 지정하지 않은 상태입니다.

    flex-grow가 없는 item은 여백을 채우기 위해 늘어나지 않았으므로 그대로 80px입니다.

    반면, flex-grow가 있는 item은 늘어나는데 그 배율이 값에 따라 다른 걸 확인할 수 있습니다.

    IE 10에서는 -ms-flex-positive: 1;과 같이 사용합니다.


    [Property #7] flex-shrink

    flex-shrink는 flex item이 줄어드는 배율을 지정합니다. flex-grow의 반대라고 할 수 있죠.

    따라서 flex-shrink로 주는 값이 크면 클 수록 item의 너비는 좁아집니다.

    이 속성도 item에게 지정하면 됩니다.

    .item:nth-child(1) {
      flex-shrink: 1;
    }
    .item:nth-child(2) {
      flex-shrink: 2;
    }
    .item:nth-child(3) {
      flex-shrink: 3;
    }

    1~3번째 item에게 각각 flex-shrink: 1~3을 준 상태


    flex-shrink값이 높으면 높을 수록 줄어든 배율이 다른 것을 확인할 수 있습니다.

    참고로 flex-shrink: 1을 줘봤자 flex-shrink를 주지 않은 다른 item과 똑같이 줄어듭니다.

    flex item은 container 너비가 좁아지면 알아서 축소된다고 했는데, 그 이유가 flex-shrink: 1이 기본값이라 그렇습니다 :>

    IE 10에서는 -ms-flex-negative: 1;과 같이 사용합니다.


    [Property #8] justify-content

    justify-content를 쓰면 flex item을 정렬할 수 있습니다. item 정렬을 책임지는 속성 성기사 뿌뿌뿡!

    flex container에게 지정하며, 값은 다음 5개 입니다.

    justify-content: flex-start;     ⇒ 왼쪽 to 오른쪽 정렬, 또는 위 to 아래 정렬 [初期値]
    justify-content: flex-end;       ⇒ flex-start의 역순
    justify-content: space-between;  ⇒ flex item이 균일한 간격으로 정렬됨
    justify-content: space-around;   ⇒ flex item이 균일한 간격으로 정렬되나, 양 끝에 그 간격의 절반만큼의 여백이 생김
    justify-content: center;         ⇒ flex item이 container의 정중앙으로 정렬됨

    justify-content: space-between


    justify-content: space-around;


    justify-content: center;


    [Property #9] align-items

    align-items는 flex item을 정렬하는 데 쓰입니다. 음? justify-content도 정렬하는 거 아니였나요?

    뭐가 어떻게 다른지 그림으로 알아봅시다.

    IE10에서는 -ms-flex-align: center;와 같이 사용합니다.

    align-items: flex-start;    ⇒ 위쪽 정렬
    align-items: flex-end;      ⇒ 아래쪽 정렬
    align-items: cetner;        ⇒ 상하좌우 가운데 정렬
    align-items: baseline;      ⇒ 첫 번째 flex item의 baseline에 맞춰 정렬
    align-items: stretch;       ⇒ container에 맞춰 flex item이 늘어남

    align-items: flex-start;

    align-items: flex-end;

    align-items: center;

    align-items: stretch;


    단, stretch의 경우 flex item의 높이를 지정한 경우에는 그것이 우선됩니다.

    위 예시화면에서도 item 01~04, 12에게는 높이값을 줬기 때문에 stretch를 줘도 늘어나지 않았습니다.


    [Property #10] align-self

    align-self도 flex item을 정렬하는 데 쓰입니다. 아, 하지만 align-items와 다른 점은 셀프서비스라는 거죠.

    즉, flex item 자체에게 이 속성을 지정하여 독립적인 정렬이 가능합니다.

    IE10에서는 -ms-flex-item-align: center;와 같이 사용합니다.

    .container {
      align-items: center;
    }
    
    .item:nth-child(1) {
      align-self: flex-start;
    }
    .item:nth-child(2) {
      align-self: flex-start;
    }
    .item:nth-child(5) {
      align-self: flex-end;
    }
    .item:nth-child(6) {
      align-self: flex-end;
    }

    container에게 center && item 01,02에게 flex-start && item05, 06에게 flex-end를 준 모습


    3. Flexbox 모델의 활용 예

    그럼 실제로 flex 속성을 활용해 레이아웃을 구현해 봅시다.

    .form-list*2 > label.form-label + input.form-input + .form-background

    flex-container안에 label과 input이 flex-item으로 있는 상태입니다.

    .form-list {
       display: -webkit-flex;
       display: -moz-flex;
       display: -ms-flex;
       display: -o-flex;
       display: flex;
      
      .form-input {
         -ms-flex-positive: 1;
         -webkit-flex-grow: 1;
         flex-grow: 1;
      }
      
      .form-background {
         position: absolute;
      }
    }

    form-label은 가만히 두고 form-input에게 flex-grow를 줬습니다.

    이렇게 되면, form-label은 가만히 있고 form-input의 크기만이 스크린에 따라 유동적으로 변합니다.

    form-list의 크기만 미디어쿼리로 조절하면 form-input은 크기가 알아서 조절되는 셈이죠.



    2) order를 활용해 반응형 레이아웃 바꾸기

    이 글에선 다루지 않았지만 order 속성을 활용한 레이아웃이 있길래 살짝 살펴봤습니다 :>

    .header > h1.logo + button.search + button.logout + button.burger + ul.nav

    이런 형태의 레이아웃이며, mobile first로 작업해 보겠습니다.

    우선 작은 화면에서는 < 검색 아이콘 + 로고 + 버거 메뉴 >가 상단에 보이고,

    버거 메뉴 클릭 시 < 네비게이션 + 로그아웃 버튼 >이 나타나게 하려고 합니다.

    그런데 html 상에서는 로고를 먼저 마크업한 상태입니다. 어쨌든 이게 제일 중요한 정보니까요!

    이럴 때 쓸 수 있는 게 바로 order 속성입니다.

    .search {
          width: 60px;
          height: 60px;
          -webkit-box-ordinal-group: -1;
          -webkit-order: -1;
          -ms-flex-order: -1;
          order: -1;
    }

    기존
    search icon에 order:-1을 준 모습

    이제 큰 화면을 스타일링해 봅시다.

    큰 화면일 때는 < 로고 + 네비게이션 + 검색 버튼 + 로그아웃 버튼 >이 보이고, 버거 메뉴는 사라지게 만들 예정입니다.

    마크업 순서는 로고+검색+로그아웃+버거+네비게이션이었으니 order로 강제 정렬합시다.

    .search { order: 2; }
    .logout { order: 1; }

    그러면 order에 따라 로그아웃과 검색 버튼이 뒤로 가 있는 것을 확인할 수 있습니다.




    댓글 0