Flexible Box Layout은 CSS의 박스 모델 중 하나로, 수평 혹은 수직으로 유연한 박스 레이아웃을 구성할 수 있습니다. 크기와 여백, 배치 등이 컨텐츠와 환경에 맞춰 자동으로 조정되기 때문에, 간단한 코드로 깔끔한 화면을 만들 수 있습니다.
쉽게 말하자면,
1) 가로 혹은 세로로 무언가를 나열할 때 유용하고
2) 크기가 고정되지 않은 유연한 컨텐츠에 잘 맞습니다.
바둑판처럼 일정한 크기로 혹은 평면적으로 구성해야 할 때는 grid가 훨씬 사용하기 쉽습니다.
이 글에서는 flex(이하 플렉스)의 구문을 중심으로 기초적인 사용법을 알아보겠습니다.
간단한 예제로 기본적인 내용을 살펴봅시다. 다음은 컨테이너 안에 3개의 박스를 나란히 배열하는 코드입니다.
.container {
display: flex;
}
<div class="container">
<div class="item">박스1</div>
<div class="item">박스2</div>
<div class="item">박스3</div>
</div>
앞에서 얘기한 것처럼 플렉스는 일종의 레이아웃입니다. 자식 요소를 어떻게 배치하고 보여줄지에 대한 방식을 정해둔 것이죠. 위 예제에서는 div.container가 레이아웃을 적용할 공간인 플렉스 컨테이너(Flex Container)입니다. 컨테이너의 자식 요소들이 플렉스 레이아웃에 따라 배치되겠지요.
참고로, 아래처럼 인라인 타입으로 설정할 수도 있습니다. 여타 인라인 요소와 동일한 방식으로 작동합니다.
display: inline-flex;
이제 HTML 코드를 보면, 컨테이너 안에 3개의 박스(div.item)가 있습니다. 각 박스가 컨테이너 안에 배치될 요소이며, 플렉스 아이템(Flex Item)이라고 합니다.
이후, 플렉스 컨테이너는 컨테이너로, 플렉스 아이템은 아이템으로 약칭합니다.
위의 기본 예제는 단순히 플렉스 레이아웃을 사용하겠다는 선언에 가까운 내용입니다. 구체적인 설정은 여러 속성을 통해 정할 수 있습니다.
플렉스 레이아웃에서 기본적으로 각 아이템은 컨텐츠에 맞춰 크기가 정해집니다. 화면과 컨테이너, 각 아이템 내 컨텐츠에 따라 각 아이템의 크기를 유연하게 늘리거나 줄이는 것이 플렉스 레이아웃의 특징인데, 이 크기의 변동을 완벽히 이해하고 예상하기는 생각보다 쉽지 않습니다.
플렉스 특유의 크기 조절 속성은 3가지가 있습니다. 기본 크기, 얼마나 확장할지, 얼마나 축소할지. 물론 width, height 등 기존의 크기 관련 속성도 사용 가능하지만, 고유 속성을 사용하면 플렉스를 더 원활하게 활용할 수 있습니다.
그럼 차례로 살펴봅시다.
아이템의 기본 크기를 지정하는 속성입니다. 너비냐 높이냐는 플렉스의 방향에 따라 달라집니다. 픽셀이나 퍼센트, em 등 수치 지정뿐만 아니라, 컨텐츠 크기에 따라 최대/최소, 맞추기 등도 가능합니다.
.item {
flex-basis: auto;
}
여기서 설정한 값은 기본 크기라는데 주의하세요. 이 값을 기반으로 컨테이너의 공간과 확장/축소 설정 등에 따라 크기가 변동합니다. 픽셀값 등 고정 수치를 넣어도 마찬가지입니다.
각 아이템의 확장 / 축소 설정입니다. 아이템을 기본 크기에 맞춰 컨테이너에 배치했을 때, 공간이 남거나 부족하다면 이 설정에 따라 각 아이템이 확장되거나 축소됩니다. 조금 더 자세히는 남거나 부족한 공간에 대한 비율 + 아이템 사이의 설정 비율에 따라 변화하는데... 일단 퉁쳐서, 가중치라고 생각하면 이해하기 편할 것 같습니다.
예를 들어, 다음과 같은 코드를 추가했다고 생각해 봅시다.
.item {
flex-grow: 1;
}
컨테이너에 공간이 남는 경우, 각 아이템은 1의 강도로 확장을 하려 합니다. 이 경우, 모든 아이템이 동일한 강도를 가지고 있기 때문에 동일한 크기로 확장됩니다.
반대로 값이 0이라면 확장하거나 축소하지 않습니다. 이 경우엔 비율을 따질 것 없이, 그냥 확장/축소하지 않습니다. 컨테이너 크기를 초과하는 경우라도요.
.item {
flex-shrink: 0;
}
예를 들어, flex-grow와 glex-shrink를 모두 0으로 설정한다면? 확장도 축소도 없으니 flex-basis에서 설정한 크기로 출력되게 됩니다.
참고로 양쪽 다 기본값은 1입니다.
편의상 많이 뭉뚱그려 설명을 했습니다. 확장/축소에 대해 더 알고 싶다면 다음 문서를 참고하세요.
위의 속성을 모아 flex로 축약해 사용할 수도 있습니다.
값이 3개라면, flex-grow / flex-shrink / flex-basis 순서로 적용됩니다. 예를 들어, 다음과 같은 구문이라면, grow = 0.5 / shrink = 1 / basis = 25%가 되겠지요.
flex: 0.5 1 25%;
값이 2개라면, 첫번째는 무조건 flex-grow가 되고, 두번째는 자료형에 따라 flex-shrink나 flex-basis가 됩니다. (CSS 자료형 기준) 숫자 타입이라면 flex-shrink, 그 외 길이나 비율 타입이라면 flex-basis로 인식되겠죠.
flex: 1 auto;
값이 1개라면, 자료형에 따라 flex-grow나 flex-basis로 인식됩니다.
앞에서 플렉스는 수평 혹은 수직으로 레이아웃을 구성한다고 했습니다. 이 방향을 flex-direction 속성으로 정할 수 있습니다.
사용할 수 있는 값은 다음 4가지입니다. 가로/세로 방향과 정/역방향까지 한번에 설정합니다.
각 값은 순서대로, 가로 정방향(좌→우), 가로 역방향(우→좌), 세로 정방향(위→아래), 세로 역방향(아래→위)로 배열하게 됩니다. 이 섹션은 설명할게 별로 없네요🙄
그냥 넘어가긴 아쉬우니 flex-direction 속성을 활용했던 예나 하나 써 두겠습니다. 플렉스 개념만 빠르게 보고 싶다면 넘어가세요.
플렉스를 이용해, 글 목록을 최신순으로 나열할지, 역순인 작성순 나열할지 사용자가 전환할 수 있는 기능을 만든 적이 있습니다.
여기서는 1월 ~ 12월을 순서대로 혹은 역순으로 보여주는 예제를 만들어 봤습니다. '반대로 정렬' 버튼을 누를 때마다, 1월 → 12월 순서와 12월 → 1월 순서가 전환됩니다.
.list {
display: flex;
flex-direction: column;
}
var currDirection = "column";
function reorder() {
if(currDirection == "column") {
currDirection = "column-reverse";
} else {
currDirection = "column";
}
var list = document.getElementById("list");
list.style.flexDirection = currDirection;
}
<input type="button" value="반대로 정렬" onClick="reorder()"/>
<div id="list" class="list">
<div class="article">1월</div>
<div class="article">2월</div>
<div class="article">3월</div>
<div class="article">4월</div>
<div class="article">5월</div>
<div class="article">6월</div>
<div class="article">7월</div>
<div class="article">8월</div>
<div class="article">9월</div>
<div class="article">10월</div>
<div class="article">11월</div>
<div class="article">12월</div>
</div>
핵심만 보자면,
1) 컨테이너인 .list의 flex-direction을 column으로 설정 (CSS)
2) flex-direction을 column / column-reverse로 토글하는 기능을 추가 (Javascript)
3) 버튼 클릭시 위 스크립트가 불리도록 구성 (HTML)
단순하고 깔끔하죠?
플렉스는 컨테이너 영역에 맞춰 각 아이템을 확장/축소해 준다고 했는데요. 공간이 부족한 경우, 각 아이템 크기를 줄이는 대신, 아이템 크기는 유지하고 줄을 바꿔 계속 출력되게 할 수도 있습니다.
기본값은 nowrap으로 줄을 바꾸지 않지만, wrap이나 wrap-reverse로 설정하면 화면에 맞춰 줄이 바뀝니다.
예를 들어, 아래는 1월 ~ 12월까지 목록을 구성하고, flex-wrap 설정만 바꿨을 때의 결과입니다.
이 중에서 wrap-reverse가 조금 독특한데요. 줄바꿈이 발생하면 아랫줄을 먼저 보여주는 방식입니다. 아이템의 정렬 순서는 바뀌지 않습니다.
앞에서 본 flex-wrap과 flex-direction을 합쳐 flex-flow로 축약할 수 있습니다.
flex-flow: row wrap;
크기를 조절하는 flex 축약과 헷갈리지 않도록 주의하세요. 저는 자주 헷갈리거든요...😪
문서 작성시 좌측 정렬, 우측 정렬, 좌우 채우기 등의 옵션이 있는 것처럼, 플렉스에서도 아이템을 어던 방식으로 정렬할지 정할 수 있습니다.
플렉스의 정렬에 대해서도 구체적으로 들어가면 내용이 참 많습니다. 메인축과 교차축, 시작점과 종료점 등 기준부터 시작해서, 사용할 수 있는 속성도 align-item, align-self, align-content 등 여러가지입니다.
여기서는 가장 기본적인 justify-content만 살펴보겠습니다.
사용할 수 있는 값은 크게 2 종류로 나누어 볼 수 있습니다. 좌우정렬처럼 한쪽 끝에서 시작하는 정렬값과 아이템간 간격(여백)을 늘려 컨테이너를 꽉 채우는 간격값입니다. 당연히 두 값을 동시에 사용할 수 없고, 어느 하나의 값만 넣을 수 있습니다.
플렉스 특유의 정렬값으로 flex-start와 flex-end가 있습니다.
justify-content: flex-start;
justify-content: flex-end;
속성 이름에서 예상되듯, 플렉스 방향을 기준으로 각각 시작점과 끝점부터 아이템을 배치하기 시작합니다. 플렉스 방향이 가로라면 왼쪽 정렬, 세로라면 위쪽 정렬이 됩니다. 리버스 방향이라면 정렬도 뒤집어집니다. 말 그대로 플렉스가 시작하는 지점을 기준으로 정렬할지, 혹은 끝나는 지점을 기준으로 정렬할지 정하게 됩니다.
기존처럼 left, right 값도 사용할 수 있지만, 플렉스 방향의 유연함을 생각하면 flex-start와 flex-end를 사용하는게 좋지 않을까 싶습니다.
알아서 아이템을 컨테이너에 꽉 채워 배치하되, 아이템 사이의 간격을 어떻게 처리할지 설정할 수도 있습니다.
사용할 수 있는 값 중 space-between, space-around, space-evenly를 살펴보겠습니다. 세 가지 모두 아이템이 동일한 간격으로 나열되는데, 외곽 여백을 어떻게 처리할지(유무와 비율)에 차이가 있습니다.
justify-content: space-between;
justify-content: space-around;
justify-content: space-evenly;
말로 설명하면 복잡하고, 적용한 그림을 보면 이해하기 쉬울 것 같습니다. 주황색 네모가 아이템, 흰색이 여백입니다.
첫번째 space-between은, 외곽 여백이 없습니다. 첫번째와 마지막 아이템이 최외곽에 찰싹 붙었죠.
두번째 space-around는, 아이템 둘레에 여백을 추가한다고 보면 편합니다. 각 아이템마다 여백이 생기기 때문에, 아이템과 아이템 사이에는 두 아이템의 여백이 더해지게 됩니다. 외곽 여백이 1이라면, 아이템 사이 여백은 2가 되겠죠.
세번째 space-evenly는, 외곽과 아이템 사이가 모두 동일한 여백을 갖게 됩니다.
이외에도 플렉스는 다양한 정렬 옵션이 있습니다. 위에서 본 justify-content에 사용할 수 있는 값도 더 있고, 정렬에 관한 다른 속성도 여러 가지가 있습니다. 자세한 내용을 알고 싶다면 다음 페이지를 참고하세요.
https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Flexible_Box_Layout