Blog/CSS

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

나나 (nykim) 2019. 1. 7. 18:46
320x100



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에 따라 로그아웃과 검색 버튼이 뒤로 가 있는 것을 확인할 수 있습니다.




728x90