[CSS] flex 사용 예시

flex는 정렬, 방향, 순서, 크기 등을 유연하게 조절할 수 있어서 복잡한 계산을 하지 않고 다양한 레이아웃을 구성할 수 있다. 팀 프로젝트로 웹페이지를 개발하면서 flex의 기능을 일부 활용했던 사례들을 정리한다.

  1. 양쪽정렬
  2. 바닥기준정렬
  3. 고정/유동적 너비
  4. 범위 초과시 줄바꿈

Vue.js로 개발하였고, BootstrapVue를 활용하였다.

flexbox는 display: flex를 가진 div태그를 말하고, flexitem은 flexbox 내의 요소들을 말한다.

양쪽정렬

아래와 같은 모달(Modal)창이 있다고 하자. 요약 정보라는 소제목과, 다른 모달창으로 넘어가는 그래프로 보기 버튼을 같은 줄에 나타내기위해 해당 div를 flexbox로 만들었다.

flex-1

위 이미지에서 표시된 부분의 소스코드는 아래와 같다. 가장 바깥 divd-flex class를 추가하여 flexbox로 만들고, justify-content-between class를 추가하여 양쪽정렬을 구현할 수 있다. 양쪽정렬 뿐 아니라 여러가지 정렬도 제공한다. (https://getbootstrap.com/docs/4.5/utilities/flex/#justify-content)

1
2
3
4
5
6
7
8
<div class="mb-1 d-flex justify-content-between">
  <span class="h5">
    <strong>요약 정보</strong>
  </span>
  <b-button size="sm" class="shadow" variant="success" @click="onClickChart">
    그래프로 보기
  </b-button>
</div>

BootstrapVue에서 d-flexdisplay: flex이며, justify-content-betweenjustify-content: space-between을 의미한다. 이와 같이 BootstreapVue에서 제공하는 (또는 Bootstrap에서 제공하는) CSS 클래스를 활용하였으며, 클래스 이름만으로 어떤 CSS를 가지는지 추측가능하다. 이 외에 자세한 사항은 공식 홈페이지를 참고하길 바란다.

바닥기준정렬, 고정/유동적 너비

아래 이미지의 표시된 부분에서 글자들이 바닥에 붙어있는 것을 볼 수 있다. 또한 입력칸 너비가 유동적이며, 만원이상, 만원이하 부분은 너비가 고정이다.

flex-2

바닥기준정렬

바닥기준정렬은 flexbox에 class="align-items-end"를 주는 것으로 쉽게 구현할 수 있다. flexbox내의 아이템들을 정렬하는 방식을 결정하는 것으로, 바닥기준정렬 외에도 여러가지를 지원한다.(https://getbootstrap.com/docs/4.5/utilities/flex/#align-items)

flex-3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="d-flex align-items-end">
  <div class="flex-1">
    <b-form-input class="mt-1" type="number" size="sm" v-model="lower" />
  </div>
  <span>
    <small class="mx-1"><b>만원</b> 이상</small>
  </span>
  <div class="flex-1">
    <b-form-input class="mt-1" type="number" size="sm" v-model="upper" />
  </div>
  <span>
    <small class="mx-1"><b>만원</b> 이하</small>
  </span>
</div>

고정/유동적 너비

다음, 고정/유동적 너비를 조절하는 것이 바로 flex라는 속성이다. 위 소스코드에서는 flex-1 class를 사용하는데, flex는 flexitem의 크기에 관련된 속성이다. 아래 css는 모두 같은 표현이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
.flex-1 {
  flex: 1;
}

.flex-1 {
  flex: 1 1 0;
}

.flex-1 {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
}

flex-grow는 flexitem의 확장에 관한 속성이며, flex-shrink는 flexitem의 축소에 관한 속성이다. 해당 값이 1이상이어야 flexbox에 맞게 확장 및 축소한다.

다시 소스코드를 보면, 입력칸 div(2번 줄)에는 flex를 주었으므로 flexbox 내에서 확장 및 축소하지만, “만원 이상”(5~7번 줄), “만원 이하”(11~13번 줄) span에는 flex 속성이 없으므로 해당 요소가 가지는 너비를 그대로(고정적으로) 가지게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class="d-flex align-items-end">
  <div class="flex-1">
    <b-form-input class="mt-1" type="number" size="sm" v-model="lower"></b-form-input>
  </div>
  <span>
    <small class="mx-1"><b>만원</b> 이상</small>
  </span>
  <div class="flex-1">
    <b-form-input class="mt-1" type="number" size="sm" v-model="upper"></b-form-input>
  </div>
  <span>
    <small class="mx-1"><b>만원</b> 이하</small>
  </span>
</div>
</div>

... 중략

<style scoped>
  .flex-1 {
    flex: 1;
  }
</style>
너비가 넓으면
너비가 좁으면

범위 초과시 줄바꿈

아래 이미지에서 표시된 공간에 검색 기록이 쭉 나열되어 있다.

flex-6

페이지 너비가 좁아지면 내부 텍스트가 줄바꿈이 된다. 너비는 유지하면서 각 검색어를 아래 줄로 내려가도록 수정하려 한다. 너비에 따라 유동적으로 너비를 변경시키는 것이 아니라, 다음 줄로 내리는 것을 구현하려면 flexbox에 class="flex-wrap을 주어서 구현할 수 있다. flex-wrap을 적용한 것과 적용하지 않은 것의 차이는 아래와 같다.

flex-8 기본
flex-7 flex-wrap: wrap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="d-flex justify-content-center pb-5 searchbar-bg-color flex-wrap">
  <span class="mr-4"><small>최근 검색 기록 (최대 5개)</small></span>
  <div
    class="d-inline-flex bg-color-white rounded pl-2 mr-3 hover-history mb-1"
    v-for="(item, index) in userHistory"
    :key="index"
    @click="onClickMoveSearch(item)"
  >
    <span class="mr-1"> </span>
    <b-button
      class="p-0 hover-danger"
      variant="light"
      size="sm"
      @click.stop="onClickDelete(item)"
    >
      <b-icon icon="x"></b-icon>
    </b-button>
  </div>
</div>

OFF THE RECORD

굳이 flex를 사용하지 않더라도 구현할 수 있는 부분들도 있었으나, 매우 유용하다고 느껴서 많이 사용해보려고 적용한 경우도 있다. 반응형 레이아웃을 구성하는데 매우 유용해 보였다. 특정 레이아웃을 구현하기 위해 flex의 속성을 이것저것 만져서 구현은 했지만, 시행착오를 통해서 구현했기 때문에 ‘이 방법이 맞다’, ‘이 속성은 이렇게 활용하는 것이다’ 라고 확답하지는 못하겠다. flex에 대해서 시행착오했던 흔적을 남기고, 누군가에게는 참고가 되어 도움이 되었으면 하는 마음에 글을 남긴다.

댓글 남기기