본문 바로가기

CSS

프론트엔드 필수 반응형 CSS 단위 em 과 rem | 예제 프로젝트를 통해 정리 하세요 ✨ by 드림코딩

언제, 어떤 경우에 어떤 unit을 쓰는게 좋은지 한번 알아보자!

 

많은 unit은 두가지 카테고리로 나눠질 수 있다.

- 절대적 unit : px

- 상대적 unit : %, v*, em, rem

 

 

언제, 어떤걸 쓰는게 좋을까?

1/ 부모요소의 사이즈에 따라서 사이즈가 변경되어야 한다면 → %, em

2/ 부모요소의 사이즈에 상관없이 브라우저 사이즈에 따라 변경되어야 한다면v*, rem

 

 

 

3/ 요소의 너비와 높이에 따라서 사이즈가 변경되어야 한다면 → %, v*

4/ font 사이즈에 따라서 사이즈가 변경되어야한다면 → em, rem

 

 

# em vs rem 어떤 차이점이 있나요?

- em: relative to parent element

- rem : relative to root element

 

em vs rem 어떤게 더 낫다라는게 없다.

어떤 design인지에 따라서, 우리가 정확하게 원하는 기능이 무엇인지에 따라서 em을 쓰는게 더 적절할 때도 있고, rem을 쓰는게 더 적절할 때도 있다.

 

 

 

ex1) 'Like' 버튼의 컴포넌트를 만든다고 해보자.

## rem 사용할 경우

버튼의 글자를 rem을 쓰게되면, rem은 root에 따라서 크기가 결정되기 때문에

page의 가장 상위 요소인 body에서 컴포넌트를 쓸 때나 다른 컴포넌트 안에서 컴포넌트를 쓸 때의 크기가 전혀 변동사항이 없다.

 

'Like'버튼의 컴포넌트는 rem을 사용하고 있기 때문에, 부모 container에 있는 폰트 크기와는 상관없이 페이지에 어떤 박스안에서 사용해도 크기가 일정하게 고정되어있다.

Like버튼이 어디에 들어있든 font-size는 동일하다.

 

 

1/ em 사용할 경우

em을 이용해서 컴포넌트를 만든다면

상위에서 썼을 때와, 부모요소에서 사용했을 때 'Like'버튼의 컴포넌트 크기 차이가 생기게 된다.

 

em은 부모요소의 font사이즈에 상대적으로 변하기 때문.

 

따라서,

- 페이지 어디에서 사용되어져도 사이즈가 그대로 고정되어야 한다면 : rem을 이용해서 스타일링 하는게 맞다.

- 컴포넌트가 어디에서 사용되느냐에 따라서 즉, 부모 요소에 따라서 유동적으로 변경되어야한다면 : em

 

 

em을 사용했을 경우에는 부모 요소인 body의 font-size가 16px이므로

  • level1은 부모의 2em이므로16 * 2 === 32px
  • level2 : 부모의 2em이므로 32px * 2 === 64px
  • level3 : 부모의 2em이므로 64px * 2 === 128px

이렇게 2배씩 계산이 되어진다.

 

## em의 단점

이렇게 폰트 사이즈가 각각 얼마인지 즉각적으로 알기가 힘들다.

em은 직관적으로 알아보기가 힘들다. 

 

 

 

2/ rem 사용할 경우

rem은 한번에 계산이 잘 된다.

root 요소(브라우저-보통 body태그)에서 16px를 이용하고 있기 때문에, 어떤 level에서 사용되느냐에 상관없이 무조건 2rem은 32px.

font-size가 고정적이다.

 

따라서, 폰트사이즈를 결정할때는 em보다는 rem을 더 선호.

 

 

 

3/ em 예시 (padding)

 

# padding이 px값일 경우

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>em vs rem</title>
    <link rel="stylesheet" href="em_demo.css" />
  </head>
  <body>
    <h1>Hello, dream coders</h1>
  </body>
</html>
/* em_demo.css */
h1 {
  display: inline-block;
  font-size: 5em;
  background-color: mediumaquamarine;
  padding: 10px;
}

font-size는 5em을 사용해서 반응형으로 만들었지만, padding은 10px로 고정되어있다. 

(대부분의 브라우저에서 'body'태그의 기본 'font-size'는 16px. 따라서 위 글자의 font-size는 80px.)

 

그래서 브라우저의 font-size를 변경하면 font-size는 변경되지만, padding은 10px로 고정되어있다.

 

 

# padding이 em값일 경우

padding도 font-size에 따라 변경시키고싶다면, 1em 이렇게 상대적인 값으로 주면 된다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>em vs rem</title>
    <link rel="stylesheet" href="em_demo.css" />
  </head>
  <body>
    <h1>Hello, dream coders</h1>
  </body>
</html>
h1 {
  display: inline-block;
  font-size: 5em;
  background-color: mediumaquamarine;
  padding: 1em;
}
 

 

1em은 현재 요소의 font-size에 상대적인 크기를 나타냅니다.

즉, padding 속성에 1em 값을 주면, 그 요소의 현재 font-size와 동일한 크기의 여백이 적용됩니다.

 

** em은 현재 요소의 font-size, 또는 부모 요소의 font-size의 상대적인 크기이다.

예시)

부모 요소의 font-size가 16px, 현재 요소의 font-size가 1em, padidng이 1em일 경우

  • 현재 요소의 font-size : 16px * 1 = 16px
  • padding : 16px(현재 요소의 font-size) * 1 = 16px

 

 

Q. 부모 요소의 font-size와 현재 요소의 font-size가 다르다면, em은 어떤 값의 상대적 크기인가?

현재 요소의 font-size를 따른다.

 

<!DOCTYPE html>
<html lang="en">
  <body>
    <h1>Hello, dream coders</h1>
  </body>
</html>
h1 {
  display: inline-block;
  font-size: 5em;
  background-color: mediumaquamarine;
  padding: 1em;
}

위 예시를 보면,

- 부모 요소(body)의 font-size : 16px

- 현재 요소(h1)의 font-size : 5em이므로 16px * 5 = 80px

- padding : 현재요소의 font-size인 80px * 1 = 80px

 

 

 

media query를 이용해서 screen마다 font-size가 변경이 되면,

font-size에 맞게 padding이 1em으로 변경되기 때문에 조금 더 반응형으로 컴포넌트를 만들 수 있다.

 

h1 {
  display: inline-block;
  font-size: 5em;
  background-color: mediumaquamarine;
  padding: 1em;
}

@media screen and (max-width: 780px) {
  h1 {
    font-size: 3em; /* 16px * 3 = 48px; */
  }
}

@media screen and (max-width: 680px) {
  h1 {
    font-size: 1.5em; /* 16px * 1.5 = 24px; */
  }
}

 

 

너비가 1~680px까지는

font-size : 16px * 1.5 === 24px;

padding : 24px * 1 === 24px;

 

너비가 681~780px까지는

font-size : 16px * 3 === 48px;

padding : 48px * 1 === 48px;

이렇게 font-size에 맞게 padding이 변경된다.

 

 

4/ em vs rem demo

브라우저의 사이즈가 작아지면 font-size를 줄이는 것으로 만들어보자.

component의 width는 50%로,

em, rem도 반응형 unit이지만, font-size에 비례해서 변하므로

contents를 유동적으로 만들기 위해서는 %를 이용하는게 더 좋다.

<!-- rem_demo.html -->
<!DOCTYPE html>
<html lang="en">
  <body>
    <section class="component">
      <header class="title">Master Front-end ✨</header>
      <p class="contents">
        Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sapiente
        veniam, nulla porro distinctio aliquid, quos quidem odio consectetur
        aperiam, delectus cum. Deserunt facilis excepturi similique natus minus
        deleniti rem sit?
      </p>
    </section>
  </body>
</html>

 

/* rem_demo.css */
.component {
  width: 50%;
  border: 1px solid burlywood;
  font-size: 2rem; /* 16px * 2 = 32px */
}

.title {
  padding: 0.5em; /* 부모요소 font-size인 32px * 0.5 = 16px */
  background-color: burlywood;
}

.contents {
  font-size: 1rem; /* 16px * 1 = 16px */
  padding: 0.5em; /* font-size인 16px * 0.5 = 8px */
}

@media screen and (max-width: 780px) {
  .component {
    font-size: 1.5rem; /* 16 x 1.5 = 24px */
  }
}

 

 

padding에 0.5em을 사용한다는 것은, 기존의 contents에 적용된 font-size의 0.5배로 계산이 되어진다.

그래서 font-size가 변경이 되면 padding이 조정이 되어진다.

  • title에서의 padding : 16px
  • contents에서의 padding: 8px

 

padding을 em을 써서 em은 현재요소의 font-size에 상대적으로 결정된다.

따라서, title의 font-size가 contents의 font-size보다 크기 때문에 조금 더 많은 padding이 들어간다.

수직적으로 정렬이 되지 않은 것처럼 보인다.

 

 

그래서 padding으로 em을 쓰는거 좋지만, 고정적인 padding을 유지하고 싶다면 rem을 사용하는 것이 좋다.

위아래는 font-size에 맞춰서 조정되도록 하는 것이 좋고 → em

양쪽은 0.5 rem을 사용해서 현재 font-size에 상관없도록 만드는 것이 좋다. → rem

.component {
  width: 50%;
  border: 1px solid burlywood;
  font-size: 2rem;
}

.title {
  padding: 0.5em 0.5rem;/* 위아래는 font-size에 맞게 조정. 양쪽은 font-size와 상관없이 고정된 값 */
  background-color: burlywood;
}

.contents {
  font-size: 1rem;
  padding: 0.5em 0.5rem;/* 위아래는 font-size에 맞게 조정. 양쪽은 font-size와 상관없이 고정된 값 */
}

@media screen and (max-width: 780px) {
  .component {
    font-size: 1.5rem;
  }
}

 

em, rem 둘 중, 꼭 1가지만 사용하기 보다는 컴포넌트의 디자인에 따라서 적절히 필요에 맞게 사용하는 것이 좋다.

 

 

5/ Final Project

이 사이트는 반응형이지만, font-size는 변경이 되지 않는다.

<!DOCTYPE html>
<html lang="en">
  <!-- head 생략 -->
  <body>
    <h1>Dream Coding</h1>
    <div class="container">
      <section class="component">
        <header class="title">Master Front-end ✨</header>
        <p class="contents">
          Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sapiente
          veniam, nulla porro distinctio aliquid, quos quidem odio consectetur
          aperiam, delectus cum. Deserunt facilis excepturi similique natus
          minus deleniti rem sit?
        </p>
      </section>
      <section class="component">
        <header class="title">Career Growth 🚀</header>
        <p class="contents">
          Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sapiente
          veniam, nulla porro distinctio aliquid, quos quidem odio consectetur
          aperiam, delectus cum. Deserunt facilis excepturi similique natus
          minus deleniti rem sit?
        </p>
      </section>
    </div>
  </body>
</html>
h1 {
  font-size: 28px;
  color: burlywood;
  margin: auto;
  text-align: center;
}

.container {
  display: flex;
  padding: 32px;
}

.component {
  border: 1px solid burlywood;
  margin: 16px;
}

.title {
  font-size: 24px;
  padding: 16px;
  background-color: burlywood;
}

.contents {
  font-size: 18px;
  padding: 16px;
}

@media screen and (max-width: 768px) {
  .container {
    flex-direction: column;
  }
}

 

 

font-size가 px로 고정되어 있으므로 브라우저 자체 font-size를 늘려도 변경되지 않는다.

 

 

 

.title에서 font-size를 rem을 사용하는 이유

- title이나 header 등의 글자들이 어떤 컴포넌트에 쓰이냐에 상관없이 동일한 사이즈를 유지하면 좋을 것 같아서 rem을 사용하는 것.

- padding같은 건 font-size에 따라서 padding도 바뀌면 좋을 것 같아서 em을 사용하고 있다.

 

h1 {
  /* font-size: 28px; */
  font-size: 1.75rem;
  color: burlywood;
  margin: auto;
  text-align: center;
}

.container {
  display: flex;
  /* padding: 32px; */
  padding: 2em;
}

.component {
  border: 1px solid burlywood;
  /* margin: 16px; */
  margin: 1em;
}

.title {
  /* font-size: 24px; */
  font-size: 1.5rem;
  /* padding: 16px; */
  padding: 1em;
  background-color: burlywood;
}

.contents {
  /* font-size: 18px; */
  font-size: 1.125em;
  /* padding: 16px; */
  padding: 1em;
}

@media screen and (max-width: 768px) {
  .container {
    flex-direction: column;
  }
}

 

이제 사이트가 글꼴 크기를 변경하면(즉, root의 font-size를 변경하면) font-size와 padding이 변경된다.

하지만 여전히 브라우저 크기가 768px보다 작으면 flex-direction이 column이 된다.

 

정말 반응형으로 만들고 싶다면, mediaquery에서 max-width도 고정적인 pixel보다는 rem을 사용하면 

글자크기가 큰 경우에는 768px보다 브라우저 크기가 더 커도 font-size에 맞게 flex-direction이 column으로 바뀐다.

@media screen and (max-width: 48rem) {
  .container {
    flex-direction: column;
  }
}

 

 

글자크기를 크게 한 경우, width가 960px임에도 flex-direction이 column으로 변경된다.

 

 

글자크기를 작게 한 경우, width가 576px에서 flex-direction이 column으로 변경된다.

 

 

이렇게, 꼭 한 가지 unit만 사용해야 한다는 건 없다.

내가 어떤 걸 원하느냐에 따라서 적절히 사용하면 된다.

 

# 정리

- box자체의 사이즈를 결정할 때는 : %, v* 또는 flexbox를 이용하면 좋다.

- 요소의 font-size를 결정할 때 :

root를 상대로 변경되어야 할 때는 rem

부모 요소에 따라서 변동이 되어야 할 때는 em

 

 

 

 

참고 자료: 드림코딩

https://www.youtube.com/watch?v=xWMKz9NCD0k&list=PLv2d7VI9OotQ1F92Jp9Ce7ovHEsuRQB3Y&index=24