flexbox로 만들 수 있는 10가지 레이아웃

Posted by in Research

기존에 사용하던 레이아웃 기법은 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으로 변경하였습니다.

상단 header 영역은 고정 height 값을 주었고, .map_wrap영역에는 flex: 1 값을 주어 확장되도록 하였습니다.
flex 아이템을 다시 flex 컨테이너로 만들어(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 속성을 주면 이 레이아웃을 간단하게 표현할 수 있습니다.

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

3. 바닥에 붙는 푸터

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

4. 중앙정렬 아이콘

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

5. 유동 너비 박스

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

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

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

6. 말줄임 + 아이콘들

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


7. 상하 정렬 롤링 리스트

normal flow에 따라 inline level elements는 왼쪽에서 오른쪽으로 하나씩 쌓이다가, 부모의 width를 넘어가면
다음 줄로 넘어가서 왼쪽에서 오른쪽으로 쌓이는 흐름을 가지고 있습니다.
여기서 normal flow의 우선순위는 좌우가 더 먼저이고, 좌우 흐름을 따를 수 없을 때 상하 흐름을 따른다는 것을 알 수 있습니다.

하지만 box가 쌓이는 순서의 흐름이 좌우 보다 상하가 더 우선시되는, normal flow에서 벗어난 UI도 있습니다.
2행 이상의 상하 정렬 리스트가 대표적인 예입니다.

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

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

8. 정렬이 다른 메뉴

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

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

폼요소에서 한글 텍스트는 한 줄로 노출되지만, 영어 텍스트는 두 줄이 노출되는 경우가 있습니다.
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으로 설정해주었습니다.

참고링크

마치며

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