기존의 웹페이지를 만들 때 사용하던 올드한 레이아웃 제작방법을 개선하고자 flexbox 가 생겨났다.
flex는 flexible의 준말로 유동적인 레이아웃을 손쉽게 만들 수 있다는 의미를 가진다.
기본 컨셉은 아주 명확하기 때문에 기존의 레이아웃을 만드는데 사용하던 table 태그나 position 또는 float 속성을 사용하는 방법의 복잡함을 고수할 필요가 없어졌다.
다만 생각보다 다양한 속성들이 있어서 정리할 필요는 있다. 이 속성을 모두 사용할 필요는 없으므로 대략적인 이해만 해 둔 후에 필요할 때마다 참고하여 레이아웃을 만들면 될 것이다.
flexbox의 기본 컨셉
container와 item들이 부모와 자식관계일 때 container에 display : flex; 속성을 줌으로서 다음과 같은 모습의 flexbox 레이아웃으로 바뀐다.
다음은 display:flex; 속성을 줄 때 브라우저 상에서 레이아웃이 어떻게 바뀌는지를 보여주는 그림이다.
이렇게 flexbox 레이아웃으로 바뀐 후 부터는 flex container와 flex item 각각에 flex에 관련된 속성을 줄 수 있는데 각각을 구분하여 각각에 어떤 속성을 적용할 수 있고 어떤 효과가 있는지 알아보도록 하겠다.
flex container 속성들 정리
.container {
display : flex; /* inline-flex */
}
앞에서 설명한 속성으로 flex 레이아웃을 설정하기 위해 기본적으로 있어야 하는 속성이다. 속성 적용 후에 자식 요소들의 배치가 inline화(한줄에 배치) 되었음을 기억하자. 주의할 점은 이 속성은 직계(direct) 자손에게만 적용된다는 것이다.
container 클래스의 직계 자손들은 flexbox 레이아웃이 적용되어 가로(inline)로 한줄 안에 배치되었으나 container 클래스의 첫 번째 직계자손의 자손은 적용되지 않고 세로로 배치되었다. (div 태그는 display : block; 이 기본 속성이기 때문이다.)
따라서 다음 코드를 추가하여 flexbox 모든 자식에게 레이아웃을 적용시킬 수 있다.
display : inline-flex; 속성을 주면 container 영역이 item에 맞게 줄어든다.
flex-direction
.container {
display : flex;
flex-direction : row; /* row-reverse, column, column-reverse */
}
container 안에서 item들의 정렬과 배치 방향을 설정하는 속성이다.
flex-direction이 row면 container 내부에서 왼쪽 정렬, 왼쪽부터 아이템이 행방향으로 순서대로 배치된다.
flex-direction이 row-reverse면 container 내부에서 오른쪽 정렬, 오른쪽부터 아이템이 행방향으로 순서대로 배치된다.
container 클래스에 height 속성을 다음과 같이 넉넉히 잡고 다음 속성들을 줘보자.
flex-direction이 column이면 아이템들은 각각 한줄을 모두 차지하며 block 속성값을 갖는 것 처럼 열방향으로 배치된다.
flex-direction이 column-reverse면 container의 아래쪽 부터 위쪽으로 채워지면서 아이템 배치순서가 아래에서 위쪽으로 바뀐다.
※ 참고 : container를 display : inline-flex; 속성으로 바꾸면 위 속성들이 어떻게 동작하는지 확인하도록 하자.
flex-wrap
.container {
display : flex;
flex-wrap : nowrap; /* wrap, wrap-reverse */
}
item들의 너비의 합이 container의 너비(현재 브라우저 창의 너비)를 초과할 때 어떻게 처리할 지를 결정하는 속성이다. 그냥 줄바꿈 속성이라고 생각해도 된다.
nowrap 은 기본값으로 브라우저의 너비를 초과해도 상관없이 아이템들이 한 줄로 표시된다.
wrap 은 브라우저의 너비를 초과한 아이템들을 줄 바꿈을 하여 다음 줄로 넘긴다.
wrap-reverse는 wrap과 같지만 아래에서 위쪽으로 배치한다.
반응형 웹에서 PC와 같은 환경에서는 메뉴가 사이드에 표시되지만 모바일 환경에서는 아래로 길게 늘어뜨려지는 경우를 본 적이 있을 것이다. 이런 것은 이 속성으로 아주 간단히 표현할 수 있다.
flex-flow
.container {
display : flex;
flex-flow : row wrap; /* flex-direction과 flex-wrap의 조합 */
}
flex-flow는 바로 앞의 두 속성을 같이 설정할 수 있는 약식 표현 속성이다. 이런 약식표현으로 border가 있음을 우리는 알고 있으므로 쉽게 이해할 수 있다.
justify-content
.container {
display : flex;
justify-content : flex-start; /* flex-end, center, space-between, space-around */
}
item과 container 간에 수평방향으로 여백을 두는 방식을 지정한다.
이 속성은 container의 display 속성이 inline-flex 라면 소용없는 속성이다. 왜냐면 inline-flex 속성을 주면 item과 container 간에 여백이 없어지기 때문이다. 어렵지 않은 속성이므로 위 그림으로 설명을 대신한다.
align-items
.container {
display : flex;
height : 100px;
align-items : flex-start; /* flex-end, center, baseline, stretch */
}
justify-content 속성이 수평 방향으로 여백을 주는 방식을 설정하는 속성이라면 align-items는 수직방향으로 item과 container 간에 여백을 주는 방식을 설정한다. 이 속성의 정확한 이해를 위해서 height 속성을 넉넉히 준 후 실험하도록 한다.
이 속성들이 어떻게 동작하는지는 그림만으로도 충분히 이해할 수 있을 것이다.
속성값 baseline은 아래 그림을 보자.
속성값이 baseline을 이해하기 위해 font-size를 달리 해 보았다. 보시다시피 폰트의 baseline을 기준으로 정렬된다. 왼쪽에 flex-start가 정렬되는 방식과 비교하면 쉽게 이해할 수 있을 것이다.
align-content
.container {
display : flex;
flex-wrap : wrap;
align-content : flex-start; /* flex-end, center, space-between, space-around, stretch */
}
아이템들을 한 줄에 다 표시할 수 없어서 다음줄로 넘김이 발생했을 때 줄 사이에 여백을 결정하는 방식을 설정한다. 따라서 이 속성은 flex-wrap : wrap; 속성이 설정되어 있어야 제대로 동작한다.
justify-content가 수평방향으로 여백을 설정한다면 align-content는 수직방향으로 여백을 설정한다. align-item이 item과 container 간에 여백을 설정하는 것이라면 align-content는 수직방향으로 item들 사이의 여백과 item과 container 사이의 여백을 설정한다. 여백이 정해지는 방향만 다르지 방식은 동일하다.
살펴본 속성들이 많기는 하지만 꽤 직관적이기 때문에 이해하기는 쉽다. 필요할 때마다 그때 그때 참조해서 사용하면 된다.
flex item 속성들 정리
order
.item {
order : 1; /* 속성값은 숫자 */
}
order 속성은 아이템이 배치될 순서를 지정한다. 속성값은 숫자며 값이 작을수록 먼저 배치된다.
order 값이 -2로 가장 작은 item2가 제일 먼저 배치되고 order 값이 100으로 가장 큰 item1이 가장 마지막에 배치되었다.
flex-grow
.item {
flex-grow : 1; /* 속성값은 숫자 */
}
flex-grow는 container에 여분의 여백이 있을 때 동작하는 속성이다. 여분의 여백이 있다면 flex-grow에 설정된 비율만큼 분배되도록 동작된다. 따라서 브라우저를 가로방향으로 늘리게 되면 flex-grow에 설정된 비율만큼씩 증가되는 것을 볼 수 있을 것이다.
4개의 item에 flex-grow를 설정해 놨다. 현재 브라우저의 너비가 여분의 여유공간이 없으므로 item들에 flex-grow가 적용되지 않은 상태다. 브라우저 창을 가로방향으로 서서히 늘려보면 container에 여백이 생기는 순간부터 이 여백이 각각의 item에게 flex-grow에 설정한 비율만큼씩 분배되는 것을 알 수 있다.
하지만 늘어난 브라우저를 다시 줄여보면 줄어드는 비율도 위와 같다. 따라서 flex-grow는 늘어나는 비율 뿐 아니라 줄어드는 비율이기도 하다.
flex-basis
.item {
flex-basis : 100px;
}
flex-basis는 item의 기본 너비를 설정한다.
그런데 이 속성을 정하면 디폴트로 flex-shrink 속성이 붙는다. 그리고 flex-shrink는 item마다 줄어드는 비율을 설정하는 속성이다. flex-basis에서 설정한 너비보다 더 줄이면 flex-shrink 속성에 설정한 비율로 줄어드는 것을 볼 수 있다.
위 그림에서 브라우저의 창을 줄이다가 container와 item의 여백이 없어진 이후에도 창을 더 줄이면 item들은 flex-basis에서 설정한 100px 이하로 줄어들 것이다. 이 때부터 flex-shrink에서 설정한 비율만큼 줄어드는데 현재 디폴트로 네 개의 아이템의 flex-shrink의 값은 동일하다. 즉 동일한 비율로 줄어드는 것을 볼 수 있다. (각각 1/4, 1/4, 1/4, 1/4 의 비율로)
주의할 점은 flex-basis를 설정해도 flex-grow는 디폴트로 주어지지 않는다는 것이다. 그래서 위 그림에서 각 item들이 100px 이상 늘어나지 않는 것이다. 만약 flex-grow를 주면 어떻게 되는지는 아래 flex-shrink 속성의 설명을 참고하도록 하자.
flex-shrink
.item {
flex-shrink : 4;
}
flex-shrink는 item이 줄어드는 비율을 설정한다. flex-basis를 설정했다면 이 값을 경계로 item의 너비가 flex-basis에서 설정한 값보다 클 때는 flex-grow가 동작하고 item의 너비가 flex-basis에서 설정한 값 보다 작을 때는 flex-shrink가 동작한다.
따라서 위와 같이 설정했다면 flex-grow 속성으로 인해 브라우저를 아무리 늘려도 container와 item 사이에 여분의 여백은 생기지 않는다.
지금까지 다양한 flexbox 레이아웃에 관한 속성들을 살펴보았다.