본문 바로가기
FrontEnd/해결완료

CSS display:flex가 가지는 한계...해결책은 Grid

by 개발자B 2024. 2. 8.

flex는 1차원 레이아웃을 벗어나기가 힘들다

기존 반응형 작업을 위해서 대부분의 작업을 display:flex를 이용해서 처리하는 케이스가 많았는데, 아쉬운 한계점이 하나 있었다.

그것은 바로 flex 속성이 1차원 레이아웃(행이 1개인 경우)는 유용하지만, 2차원이 되는 순간부터는 크기 조절하는데 불편함이 있다.

아래 예시 코드 참고

 

위와 같이 한줄에 동일한 크기의 박스를 3개를 두는 레이아웃을 잡는다고 가정해보면,

한 줄에서는 각 col에 flex:1; 이라는 속성을 부여함으로써 동일한 크기로 자동적으로 나뉘도록 설정할 수 있다.

 

<div class="wrap">
    <div class="row">
        <div class="col">
            <div class="box">box 1</div>
        </div>
        <div class="col">
            <div class="box">box 2</div>
        </div>
        <div class="col">
            <div class="box">box 3</div>
        </div>
    </div>
</div>

<style>
    .wrap {
        margin: 80px;

        padding: 40px;
        width: 800px;
        border: 1px solid #c8c8c8;
    }
    .row {
        display: flex;
        gap: 8px;
    }
    .col {
        flex: 1;
    }
    .box {
        width: 100%;
        height: 200px;
        background: #b2d5e0;
    }
</style>

 

하지만 3 x 2의 배열을 하고 싶다면 어떻게 해야할까?

가장 명확한 방법은 .row를 두개로 쪼개는 방법이지만, 이 경우 프론트 처리하면서 반복문을 돌리는 과정에서 더 귀찮은 조건식이 들어간다.하나의 row 안에서 6개의 col을 둔채로 flex만으로 조절을 한다면 calc를 이용해서 크기를 조절해줘야한다.

 

.row {
    display: flex;
    gap: 8px;
    /*행 넘침 설정*/
    flex-wrap: wrap;
}
.col {
    /*크기 조절*/
    flex: 1 1 calc(33.333%);
    max-width: 33.333%;
}

 

이론상 감싸는 row에 wrap 속성을 부여하여 줄바꿈이 일어날 수 있게 하고

col에 크기만 정확하게 준다면 문제 없이 3*2로 배열 될 것 같지만, 실제론 그렇지 않다.

문제가 되는 것은 바로 .row에 들어있는 gap 속성이다.

실제로 구현된 화면을 보면 이렇게 보인다.

 

gap을 계산식에 포함하여 너비를 강제로 조정하는 경우 계산해보면 

박스1과 박스2사이, 박스2와 박스3사이 총 두 번의 여백이 들어가게 되는데. 

그러면 16px이 되고, 박스 하나의 크기는 (100% - 16px)/3을 한 값이 들어가야한다.

만약 모바일 환경에서는 2*3의 배열로 나와야한다면 여백의 수를 기반으로 계산식을 또 바꿔줘야한다.

 

 

따라서 우리는 좀 더 쉽고 간결하게 2차원의 배열을 사용하기 위해 반드시 Grid를 사용해야만 한다!

 

Grid 속성이란?

Grid는 flex의 좀 더 심화버전이라고 생각하면 된다. flex가 가지는 이런 한계점을 보완해서 온 대안이라고 생각하면 된다.

아까의 예제를 그대로 응용해서 3*2 배열의 레이아웃을 grid로 구현해본다면 이렇게 적용할 수 있다.

 

.row {
    display: grid;
    gap: 8px;
    grid-template-columns: 1fr 1fr 1fr;
}
.col {
    /*기존 크기 계산식은 모두 필요 없다*/
}

 

부모 인 .row에 grid속성을 작성하고 한줄에 들어가야할 배열을 지정해 준것만으로도 깔끔하게 아래와 같은 형태로 구현이 되었다.

여백이 있다고 해서 자식속성에 복잡하게 width를 calc로 넣어줄 필요도 없으며, 반응형 작업시에도 grid-template-columns 속성 하나만 교체하면 쉽게 배열을 변경할 수 있다.

구현된 실제 화면

 

그동안 grid를 사용하지 않은 이유

첫번째 이유는 새로운 것을 또 적용하는 것은 귀찮기 때문이다.

생각보다 이게 큰 이유는, 어떤 곳은 한줄이라 flex로 처리하고 어떤 곳은은 2행 이상이기 때문에 grid를 병행한다는 것 자체가

속성을 모두 외워야 한다는 부담감이 있다. 특히 이제 막 퍼블리싱을 시작한다거나 css에 서툰 이들이라면 굉장히 골치 아픈 이유가 된다.

 

 

 

두번째 이유는 웹사이트의 레이아웃을 잡는 경우 의미 단위로 끊어가다보면 2행을 넘는 경우가 적기 때문이다.

html 퍼블리싱만으로 개발하는 경우 대부분 하나의 의미 섹션 안에서 두개 이상의 행을 다양한 크기로 다뤄야할 정도의 일이 거의 없기 때문이다. (행이 넘어가는 케이스가 생기는 경우 row를 쪼개버리면 그만이기도 하다)

 

하지만 컴포넌트 형태로 반복적으로 뽑아줘야하는 케이스라면

flex가 가지는 한계점 때문에 머리가 깨질거 같은 순간이 분명 찾아올 것이다.

 

마치며

grid를 자유자재로 쉽게 쓰기 위해서 다양한 속성들이 있지만,

정말 이것만 알고 있어도 실무에서 응용하는데 문제 없다고 하는 것들을 모아서 다음에 자세히 다뤄보려고 한다.

 

 

FE 해결 완료된 이슈

 

모바일 웹에서 주소창 높이 만큼 화면이 가려지는 이슈

작업환경 Vue3 / Vite 사용언어 JS, CSS 브라우저 Safari, iOS 이슈상황 모바일 화면의 높이를 디바이스 화면크기와 동일하게 적용하는 과정에서 브라우저의 주소창 높이만큼 화면이 가려지는 이슈 일

developer-b.co.kr