기존에 사용하던 레이아웃 기법은 display, float, position으로 컬럼 레이아웃을 표현하는 데 한계가 있고 구현 방법이 복잡한 문제가 있었는데요. 마크업 개발자들이 종종 “이것은 구현이 어렵습니다.” 라고 얘기했던 이유 중 하나이기도 했습니다.
flexbox 모델의 장점을 한 마디로 표현하면 “복잡한 계산 없이 박스의 크기와 순서를 유연하게 배치할 수 있다.” 라고 정리할 수 있습니다. 정렬, 방향, 순서, 사이즈 등을 유연하게 조절하기 때문에 별도의 분기 처리가 줄어들고, CSS만으로 다양한 레이아웃 구현이 가능합니다. PC는 IE10이상 대응시, 모바일에서는 Android, IOS 거의 모든 버전에서 적용이 가능합니다. (https://caniuse.com/#feat=flexbox)
기존 작업방식과 차이점을 중심으로 각 레이아웃에 대해 하나씩 살펴보도록 하겠습니다.

예제

URL : https://codepen.io/witblog/full/rrGjPx

  1. 스크롤이 없는 100% 레이아웃
  2. 네비게이션
  3. 바닥에 붙는 푸터
  4. 중앙정렬 아이콘
  5. 유동 너비 박스
  6. 말줄임 + 아이콘들
  7. 상하 정렬 롤링 리스트
  8. 정렬이 다른 메뉴
  9. 폼 타이틀 수직중앙정렬
  10. 가로세로 비율을 유지하는 반응형 박스

1. 스크롤이 없는 100% 레이아웃

부동산 PC 개편 레이아웃은 싱글 페이지 레이아웃으로 구성되어 있습니다.
페이지 전체에는 스크롤이 없는 형태로, 영역 내부에서만 스크롤이 생성됩니다.
기존에 flex 속성을 쓰지 않은 경우에는 html 최상위에서부터 height: 100%를 주면서 상속받게 하고,
하위 영역들에는 height: calc(100% – 60px)과 같이 계산해서 지정해주는 방식으로 적용하였습니다.
또는 일정 padding을 주면서 margin을 음수로 주면서 맞추기도 하였습니다.
flex 속성을 쓰면 100% 높이 지정의 번거로움에서 벗어날 수 있습니다.

전체 래퍼(.wrap)에 absolute를 주어 고정하고 width, height를 100%로 잡아줍니다.
flex 속성에서 flex-direction 속성은 기본 값이 row이기 때문에 수직으로 적용하기 위해, column으로 변경하였습니다.

.wrap {
    display: flex;
    flex-direction: column;
    position: absolute;
    width: 100%;
    height: 100%;
}

상단 header 영역은 고정 height 값을 주었고, .map_wrap영역에는 flex: 1 값을 주어 확장되도록 하였습니다.
flex 아이템을 다시 flex 컨테이너로 만들어(display: flex) 하위 요소인 .map 에서도 다시 flex: 1을 주었습니다.

.map_wrap {
   flex: 1; /* flex: 0 0 1 */
   display: flex;
}
.map {
   flex: 1;
}

flex: none | [ <‘flex-grow’> <‘flex-shrink’>? || <‘flex-basis’>
기본 값 = flex: 0 1 auto
none = flex: 0 0 auto와 같다.
auto = flex: 1 1 auto와 같다.
initial = flex: 0 1 auto와 같다.
정수 = flex: 정수 1 0과 같다.

작업하면서 궁금했던 부분이 flex-basis가 auto일 때와 0일 때의 차이점이었는데요,
auto인 경우에는 컨텐츠 길이에 따라 영향을 받는다는 것을 알 수 있었습니다.

2. 네비게이션

네비게이션과 같이 왼쪽에 일부 내용을 표시하고 나머지 내용은 오른쪽에 나타낼 때, 기존에는 float 또는 absolute를 사용했었습니다.
그러기 위해서는 float을 해제하거나 부모에 relative를 주어야 하는 등 추가 작업이 필요했습니다.
플렉스 아이템에 margin: auto 속성을 주면 이 레이아웃을 간단하게 표현할 수 있습니다.

.header {
   display: flex;
}
.logo,
.search,
.gnb {
   flex: 0 0 auto; /* flex:none */
}
.gnb {
   margin-left: auto;
}
.search {
   display: flex;
}
input {
   flex: 1;
}

margin: auto를 사용하면 auto 값을 갖는 방향(왼쪽, 오른쪽 또는 양쪽 모두)으로 빈 공간을 채우게 됩니다.
자동마진에 대한 자세한 내용은 “Flexbox 이해: 당신이 알아야 할 모든 것” 글에서 자세히 설명되어 있으니 참고해주세요.
logo, search, gnb 영역은 고정 width 값을 가지므로 grow, shrink 값을 0으로 고정하였습니다.
검색 영역에서도 input이 좌측으로 체워질 수 있도록 flex:1을 주었습니다.

3. 바닥에 붙는 푸터

컨텐츠 높이가 짧을 때에도 푸터가 아래로 붙는 레이아웃의 경우,
플렉스 아이템에 margin-top: auto를 적용하면, 별도의 min-height를 잡지않아도 브라우저 높이만큼을 잡을 수 있게 됩니다.

main {
   display: flex;
}
footer {
   margin-top: auto;
}

4. 중앙정렬 아이콘

아이콘 중앙정렬은 table, absolute, transform 속성 등의 여러가지 방법으로 구현가능 하지만,
flex layout 내부의 요소에는 간단하게 margin: auto 속성을 통해 중앙 정렬을 만들 수 있습니다.
또는 flex 컨테이너에 justify-content, align-items를 중앙으로 배치하는 방법으로도 가능합니다.

.item_list {
   display: flex;
}
.icon {
   margin: auto;
}
.item_list {
   display: flex;
   justify-content: center;
   align-items: center;
}

5. 유동 너비 박스

부동산 필터 박스는 컨테이너 길이 및 컨텐츠의 길이에 따라 유동적인 박스입니다.
flex 아이템의 기본 값을 적용하여 기본적으로 컨텐츠 길이에 맞게 배치되고, 컨테이너의 길이가 짧을 경우에는 줄어들 수 있도록 하였습니다.

.filter {
   display: flex;
}
.filter_box {
   flex: 0 1 auto; /* flex 기본 값 */
   max-width: 300px;
  ...
}

마크업 순서와 관계없이, 보여지는 순서를 변경을 해야할 경우는 order 속성을 적용할 수도 있습니다.

.filter_box:nth-child(3) {
   order: -1;
}

order 기본 값 : 0
값이 낮을 수록 앞으로 위치

6. 말줄임 + 아이콘들

기존에 우측에 아이콘이 유동적으로 붙는 컨텐츠의 말줄임을 구현하려면 float과 overflow 속성을 활용했습니다.
float에 인접한 요소에 overflow: hidden을 주면 아이콘의 개수에 관계없이 유동적으로 100%를 채울 수 있었기 때문인데요,
이 속성은 순서상 float이 꼭 우선 적용되어야 가능한 레이아웃이기 때문에 순서가 뒤바뀌는 이슈가 있었습니다.
inline-flex 속성을 활용하면 순서대로 적용할 수 있습니다.
inline-flex는 inline-block과 유사하게 inline-level로 배치되면서, 내부에서 flex container를 생성합니다.

<div class="title_wrap">
  <h3 class="title">조건에 맞는 총10000000000000개의매물이있습니다.</h3>
  <span class="school_type" role="img" aria-label="가정"><i class="sp_icon"></i></span>
  <span class="school_type" role="img" aria-label="통학차량"><i class="sp_icon"></i></span>
  <span class="school_type" role="img" aria-label="공립"><i class="sp_icon"></i></span>
</div>
.title_wrap {
   display: inline-flex;
   max-width: 100%;
}
.title {
   flex: 1;
}

7. 상하 정렬 롤링 리스트

normal flow에 따라 inline level elements는 왼쪽에서 오른쪽으로 하나씩 쌓이다가, 부모의 width를 넘어가면
다음 줄로 넘어가서 왼쪽에서 오른쪽으로 쌓이는 흐름을 가지고 있습니다.
여기서 normal flow의 우선순위는 좌우가 더 먼저이고, 좌우 흐름을 따를 수 없을 때 상하 흐름을 따른다는 것을 알 수 있습니다.
하지만 box가 쌓이는 순서의 흐름이 좌우 보다 상하가 더 우선시되는, normal flow에서 벗어난 UI도 있습니다.
2행 이상의 상하 정렬 리스트가 대표적인 예입니다.

위 그림과 같은 순서를 만들기 위해서는 세로영역에 있는 리스트들을 부모로 한 번 더 감싸줘야합니다.
그렇게 되면 depth가 깊어지게 되고, UI가 변경 됐을 때 해당 부모영역도 수정해야합니다.
flex-direction의 column 속성 값을 이용하면 부모영역으로 감싸지 않고도 위의 흐름을 표현할 수 있습니다.

.photo_container {
   overflow: hidden;
}
.photo_list {
   display: flex;
   height: 500px;
   flex-flow: column wrap;
   align-content: flex-start;
}
.photo_box {
   flex: 0 0 206px;
}

align-items 기본 값: stretch
flex-flow: <‘flex-direction’> || <‘flex-wrap’>
flex-wrap 기본 값: nowrap

8. 정렬이 다른 메뉴

라인TV 모바일웹의 탭 메뉴는 좌우 텍스트 정렬이 다르게 들어가는 레이아웃입니다.
기존에는 가장 왼쪽과 오른쪽에 있는 메뉴에 각각 text-align의 속성 값인 left와 right를 주어 양끝에 붙도록 만들었고,
중앙 메뉴에는 center 값을 주었습니다.
하지만 flex를 이용하면 메뉴 각각마다 text-align 속성 값을 다르게 줄 필요없이
justify-content 속성만으로 아래 레이아웃을 구현할 수 있습니다.

.tablist {
   display: flex;
   justify-content: space-between;
}

9. 폼 타이틀 수직중앙정렬

폼요소에서 한글 텍스트는 한 줄로 노출되지만, 영어 텍스트는 두 줄이 노출되는 경우가 있습니다.
flex와 align-items의 center속성 값을 이용하면 텍스트가 한 줄이든지 여러 줄이든지 상관없이 중앙정렬을 할 수 있습니다.

.title {
   display: flex;
   align-items: center;
}

10. 가로세로 비율을 유지하는 반응형 박스

라인TV 모바일웹에서는 디바이스 해상도에 따라 크기가 달라지는 반응형 박스를 사용합니다.
.item의 width 값을 %로 주고, <img>의 width와 height를 100%로 줘서 반응형 박스를 만들었습니다.
하지만 .item 내부에 <img>가 없을 때 .thumb의 height가 0이 되어버리는 문제가 생겼습니다.
이를 해결하기 위해 .thumb:before에 padding-top의 속성값으로 이미지 세로비율에 해당하는 %를 할당하여,<img>가 없더라도 height가 유지될 수 있도록 했습니다.
하지만 이러한 방식은 이미지 크기가 변경되면 가로세로 비율을 다시 계산하여 padding-top 속성값을 바꿔줘야한다는 번거로움이 따릅니다.
flex를 사용하여 위의 반응형 박스를 구현하면, <img>가 없을 때 가상요소로 padding-top을 주지 않아도 해당 영역이 유지됩니다.
.title의 flex: none와 flex-basis: 34px를 축약해서 flex: 0 0 34px로 쓸 수 있지만, 의도를 더 명확하게 나타내기 위해 flex: none를 사용하였습니다. flex-basis값을 우선 적용하기 위해 min-height는 0으로 설정해주었습니다.

.channel_list {
   display: flex;
   flex-flow: wrap column;
}
.item {
   display: flex;
   flex-direction: column;
   flex: 1 1 33.3%;
}
.thumb {
   flex: 1 1 0;
}
.title {
   flex: none;
   flex-basis: 34px;
   min-height: 0;
}

참고링크

마치며

flexbox 속성이 나온지는 꽤 되었지만, 이론적으로만 접하고 실무에서 적용하기 쉽지 않았던 것이 사실입니다.
PC에서도 서비스별 브라우저 대응이 업그레이드(IE10이상) 되어서, 장점이 많은 flexbox를 다양하게 활용할 수 있었으면 좋겠습니다.
궁금한 점이 있으시거나 다른 좋은 사례들이 있다면 알려주세요. 감사합니다.


0개의 댓글

답글 남기기

아바타 플레이스홀더

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다