📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄

[CSS] 반응형 웹을 위한 display: flex 이해하기

정의

그동안 display 속성하면 inline, inline-block, block 이 3가지만 알고 있었다.

하지만 반응형 웹을 만들기 위해서 필수로 알아야하는 게 바로 display: flex 이다.

이 속성은 화면이 줄어들고 늘어남에 따라 변화하는 반응형 웹을 조금 더 쉽고 효율적으로 만들기 위해서 필요한 준비물이라고 보면 되겠다.

 

display: flex를 주게 되면, block 속성을 가진 엘리먼트들도 마치 float를 먹인 것처럼 flex 안으로 들어온다.

개인적으로 flex를 줄 때, 엘리먼트를 젤리화한다고 생각한다. 뭔가 젤리를 만졌을 때 유연하고 말랑해서 모양 변화가 쉽기 때문에 이런 식으로 자연스럽게 연상하게 되는 것 같다. (이해를 위한 나만의 방식이다)

 

flex의 속성인 flex-direction이나 justify-content, align-items 등 여러 가지 속성들의 특징들은 검색만 해도 쉽게 알 수 있는 부분이기 때문에 어떤 식으로 쓸 때 좋은지에 대해, 혹은 나를 포함하여 많은 사람들이 헷갈리는 부분들을 flex를 이해하는 겸 몇 가지 적어보려고 한다.

 

이해

<div>
  <span></span>
  <p></p>
</div>

우선 html은 간단하게 이렇게 주었다. 전체 div 안에 span과 p를 넣어주었다.

 

block들의 가로 정렬

div {
  width: 300px;
  height: 300px;
}

span {
  display: block;
  width: 100px;
  height: 100%;
}

p {
  width: 200px;
  height: 100px;
}

[flex를 이용하지 않았을 때]

CSS를 위처럼 주게 되면, span이 block화 되었고, height 값 또한 100%를 줬기 때문에 p가 div 밑으로 밀린 것을 알 수 있다. 만약 p를 div 안에, span 옆에 나란히 두고 싶을 때 flex를 배우기 이전의 우리라면 span과 p에 inline-block을 주었을 것이다. 더군다나 inline의 특성상 엘리먼트 간에 여백이 생기기 때문에 div의 width 값을 더 늘려야 할 수도 있다.

 

div {
  width: 300px;
  height: 300px;
  display: flex;
}

span {
  display: block;
  width: 100px;
  height: 100%;
}

p {
  width: 200px;
  height: 100px;
}

[flex를 이용할 때]

달라진 게 있다면 div에 display: flex가 들어갔다는 점이다. 그 외에 건드린 것은 없다.

이렇게 되면 span과 p가 block임에도 불구하고 나란히 div안에 여백없이 딱 들어오는 것을 볼 수 있다.

위에서 flex를 젤리라고 표현한 것처럼 flex를 부모 태그에 주는 순간 자식 태그가 무슨 속성이든간에 자기 안으로 모두 딱 달라붙게 한다.

 

flex안의 자식 태그 크기는 그들의 비율에 맞게!

div {
  width: 300px;
  height: 300px;
  display: flex;
}

span {
  width: 2000px;
  height: 100%;
}

p {
  width: 1000px;
  height: 100px;
}

이번엔 span과 p의 width 값에 주목해봐야 한다. 전체 div의 width는 300px인 반면, span은 2000px, p는 1000px를 주었다. 결과는 어떻게 될까?

 

div를 뚫고 3000px 만큼 나가는 것이 아니라, 300px 안에서 2:1의 비율로 공간을 자동으로 배치하게 된다. 이는 flex의 역할로 전체 width 값에 해당 엘리먼트의 width 값을 나눈 것만큼의 width 값을 주입한다.

 

align-items와 align-content 비교

align-items와 align-content 둘다 flex의 Y축에 관한 속성이라 간혹 둘을 헷갈리는 경우가 종종 있다. 

이 둘을 구분짓는 핵심은 바로 "content"에 있다. flex를 주게 되면 자식 엘리먼트들은 부모의 크기에 맞게 같은 여백을 두며 서로의 간격을 유지하게 된다.

 

align-items는 이러한 여백을 그대로 유지한 채 정렬을 해주는 기능이다.

위의 그림에도 보면 여백은 그대로 유지된 채 엘리먼트 '덩어리'를 상-중-하로 정렬시키고 있는 걸 볼 수 있다.

반면 align-content는 이름에도 나와있듯이 content에 더 집중되어 있다.

align-items에서는 여백을 지켜줬다면, align-content는 여백을 지켜주되 여백보다는 엘리먼트 자체에 집중한다.

그림에서도 보면 align-items는 뭔가 딱 굳어있다면, align-content는 자유롭게 느껴질 것이다.

 

flex-start나 center 같은 경우 align-items와 동일하게 여백을 인정하며 정렬되지만, space-between 등의 간격을 조절하는 속성의 경우 그들의 여백을 무시하게 된다. 자신의 레이아웃에 여백이 필요하다면 간단히 align-items만 줘도 되지만, 여백이 필요없다면 과감히 align-content를 주는 게 좋다고 생각한다.

 

column과 wrap로 보는 여백의 차이

flex-direction: column은 단순히 엘리먼트들을 수직화시키는 기능을 한다.

flex-direction: row인 상태에서도 수직화를 시키는 방법이 있는데, 바로 flex-wrap: wrap을 주는 것이다.

또한, wrap을 준 다음에 기억해야 할 것은 width 값을 100% 혹은 행의 개체 수 / 100% 만큼 width 값을 줘야 한다.

 

<div id="wrap">
  <div class="box">
    <h1>제목입니다</h1>
    <p>내용입니다</p>
    <span>추가내용입니다</span>
  </div>
</div>

예를 들면, 이런 html 태그가 있다고 하자. 이것을 앞에서 말한 두 가지 방법으로 수직화 시켜보겠다.

 

#wrap {
  width: 500px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
}

.box {
  width: 50%;
  height: 300px;
  margin: 10px;
}

가장 간단하게 #wrap에 flex-direction: column을 주었고, 결과를 보면 깔끔하게 수직화된 것을 볼 수 있다.

하지만, #wrap에 height: 1000px를 준다면 어떻게 될까? 그냥 첫 번째 결과에서 길이만 길어질 뿐, 변하는 것이 없다.

만약 수직화를 시키되, 1행과 2행에 같은 여백을 주고 싶다면 column이 아닌 row에 wrap을 줘보자.

 

#wrap {
  width: 500px;
  height: 1000px;
  margin: 0 auto;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.box {
  width: 55%;
  height: 300px;
  margin: 10px;
}

위의 값과 달라진 것은 flex-direction에 row를 줬다는 점 (기본값이 row라 굳이 안 줘도 되지만, 명확하게 하고 싶어서 넣었다), flex-wrap: wrap을 준 것, box 클래스에 width 값을 50% 이상으로 줬다는 점이다.

box 클래스에 width 값을 50% 이하로 주게 되면, 같은 행에 배치되기 때문에 50% 이상 혹은 편하게 100%로 주는 게 좋다. 결과를 보게 되면 수직화 된 엘리먼트 간에 동일한 여백이 생긴 것을 확인할 수 있다.

 

사실 이 방법은 column처럼 수직화시키는 게 아니라, row인 상태의 엘리먼트끼리의 width 값이 100%를 넘게 돼서 wrap의 속성에 맞춰 줄바꿈되는 원리이다. (사실상 밀려났다고 보면 된다)