반응형 디자인

김수정·2020년 3월 25일
15

CSS 끝내기

목록 보기
8/8

모바일 시대에 접어들면서 여러가지 다양한 크기의 기기가 많이 생겨났습니다. 이에 따라 기존 고정형의 디자인으로는 어떤 크기의 스크린에서 가독성이 급격히 떨어지거나 여백이 많이 생겨버리는 등 웹사이트를 원활히 사용하기 어려워졌습니다.

방법은 여러가지이므로 꼭 반응형만 맞는 답도 아닙니다.
그러나 이번 주제에서는 반응형에 대해 고민해보겠습니다.

media query

미디어 쿼리는 디바이스의 크기에 따라서 다른 css를 적용할 수 있게 해줍니다. 이 것이 도입되면서 화면에 맞는 레이아웃을 짜는 것이 많이 자유로워졌습니다. 원하는 분기점(break point)을 만들어 해당 사이즈의 화면에서 원하는 css를 적용합니다. 모바일 먼저 작성하는 방식이라면 min-width 방식으로, pc 먼저 작성하는 방식이라면 max-width로 틀을 짭니다.

주의할 점은 왠만하면 미디어 쿼리를 쓰지 않고 유동적으로 작성하는 게 좋으며, 유동적으로 작성했음에도 무너지는 부분들만 작성하는 것이 좋습니다. 많을 수록 기억해야 하거나 수정할 때 살펴야 할 것이 많을 테니까요. 놓는 위치도 여러 방법들이 제안됩니다만, 제 경험상 해당 요소 아래에 쓰는 것 이 가장 좋았습니다.
같은 미디어쿼리 별로 모아봤자 css만 모여 있어서는 그 것의 동작과 모습이 머릿속에 그려지지 않고, 또 기존 소스와 떨어져 있으므로 보기도 불편합니다.

@media screen and (min-width: 800px) { 
  .container { 
    margin: 1em 2em; 
  } 
} 

viewport

이 메타태그는 모바일 브라우저 들에게 화면 너비를 기기의 너비로 설정하게 합니다.
모바일 기기는 자체적으로 자기들의 뷰포트를 정해놓았었기에 이 설정이 있어야 미디어 쿼리가 의도대로 동작합니다.
반응형 디자인의 시작입니다.

<head>
  <meta name="viewport" content="width=device-width,initial-scale=1">
</head>

attributes

  • initial-scale: 처음 렌더링 될 때 어느정도 확대할지를 정함
  • height: 뷰포트의 높이를 구체적으로 설정함
  • minimum-scale: 최고로 축소했을 때 단위를 정함
  • maximum-scale: 최대 확대 단위를 정함
  • user-scalable: 확대 기능 제공 여부

반응형 레이아웃

모든 기기의 사이즈에 대응하여 고정 값으로 레이아웃을 짜는 것은 현실적으로 불가능하고, 한 기기에서도 창 크기를 자유롭게 조절할 수 있다면 역시 고정값으로 대응할 수가 없습니다. 이에 따라 유동적인 코딩 개념은 꼭 필요합니다.

wrapper

어떤 화면이든 전체를 꽉 채우겠다는 디자인이 아니라면, 보통의 경우 일정 크기까지만 커지는 것으로 제한합니다. 너무 가로로 긴 화면도 가독성이 떨어지기 때문에 디자인적으로도 필요한 조치라고 생각합니다.

저 wrapper들을, l-wrapper, wrap, container, wrap-box 등 다양하게 불리는, 기기마다 다 다르게 설정해줄 수는 없겠죠? 유동적으로 짜 봅시다. 이 클래스는 전체 레이아웃을 조정하는 역할을 하므로 자식 선택자나 다른 꾸미는 속성을 섞지 않는 것이 좋습니다. 오로지 전체 영역을 바꾸는 용도의 것들만 적도록 합니다.

.l-wrapper {
  width: 1000px;
  max-width: calc(100% - 40px);
  margin: 0 auto;
}

width값으로 디자이너가 정한 wrapper값을 적습니다. 이는 웹버전에서의 컨테이너 역할을 할 것입니다.
max-width는 모바일 래퍼용으로 적은 것입니다. 모바일에서 전체 영역을 다 채우겠다면 100%로 해도 좋지만 보통 기본적으로 가독성을 위해 양 옆을 일정부분 떼는 걸 기본 형태로 가져가므로 그 양쪽 값을 100% 에서 빼줍니다.
margin: 0 auto는 블록요소를 가운데 정렬하는 방법인 거 아시죠~?

responsive contents

이미지, 비디오, iframe나 가로세로 비율이 유지되어야 하는 div 등의 경우에 필요한 조치입니다.

브라우저의 width에만 반응하여 콘텐츠를 조절할 때

해당 요소가 자체적으로 비율이 유지되는 img 태그 같은 경우에는 width값에만 반응하도록 해주어도 유지가 잘 되겠죠.
max-width값으로 최대 크기를 퍼센트로 정해놓으면 그 다음부터는 width에 반응하게 됩니다.

img {
  max-width: 100%:
} 

더 나아가 <picture> 태그를 이용하여 이미지를 미디어쿼리와 접목하듯이 사용할 수 있으나 IE11에서 지원하지 않습니다..
IE를 버리게 되면 생각해 보지요...

브라우저 width + 콘텐츠의 비율에 맞춰서 크기를 조절할 때

요소가 자체적으로 비율을 유지할 수 없는 비디오나 iframe, div 같은 요소들은 다른 방법이 필요합니다.
우선, 콘텐츠의 비율을 구해야겠죠.

비율은 상대적인 값을 구하는 것입니다. 따라서 기준점을 분모에, 상대값을 분자에 놓으면 비율이 나옵니다.
따라서 여기서는 가로를 기준으로 세로의 비를 알길 원하는 것이니까 아래와 같이 구합니다.

콘텐츠 비율 구하는 공식
세로 / 가로 * 100

세로와 가로의 실제값으로 나누면 비가 나오고 * 100을 해주어 백분율로 바꿉니다.
그리고 콘텐츠의 높이값에 퍼센트를 적용해줘봤자 가로에 비례한 비로 적용되지 않으니 wrapper를 감싸 padding-top으로 공간을 만들어주고,
그 안의 요소를 position:absolute로 넣어줍니다.

.iframe-wrapper {
  position: relative;
  padding-top: 100%; /* 정사각형 */
}

iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

element의 width는 고정인데 뷰포트width 크기에 맞춰 height이 바뀌어야 하는 경우

width가 %로 잡히거나 하나의 요소만 비율을 맞게 줄이려면 위의 방법들로도 충분합니다. 그런데 간혹 width값은 고정인데 세로값만 뷰포트에 맞춰 바꿔야하는 까다로운 경우가 있습니다. 그 때는 아래의 공식으로 해결합니다. calc를 중복으로 사용하면 css로도 가능하지만 IE11은 calc 중복이 동작하지 않습니다..

height = (maxHeight - minHeight) / (maxWidth - minWidth) * 100vw

1) 비율을 구하는 원리
먼저 비율을 구하려면 기준이 되는 것이 분모가 되고, 그 기준에 따라 상대적으로 적용되는 값이 분자가 되어야 합니다.
반응형은 브라우저의 width값이 변하는 것을 기준으로 무언갈 바꾸니까 이번 경우에서는 구하려는 height의 변화량에서 원하는 뷰포트의 범위의 변화량을 나눠줍니다.

2) 비율이 일정한 상태의 특정 값을 구하는 원리
비율에 맞는 특정 값을 알기 위해서는 현재 우리의 기준수치 * 비율 을 해주면 구하려는 값을 얻을 수가 있습니다.
비율은 0~1사이의 값이므로 우리가 현재기준값을 무엇으로 곱해주냐에 따라 0부터 최대값까지 비율에 맞는 값이 나오죠. 미디어쿼리로 최소, 최대 width값의 제한을 주고 현재기준값을 뜻하는 100vw만 곱하면 될 거 같은데 왜 100vw에서 minWidth를 빼줄까요? 그건 아래에서 설명하겠습니다.

반응형 typography

absolute unit

px

절대값이므로 이해하기가 쉽고, 사용하기 편한 px은 반응형에 적합하지 않습니다. 어떤 크기의 화면이든, 어떤 기기이든지 간에 변하지 않고 계속 그 값을 유지하기 때문입니다. 유저가 글자크기 변경도 하지 못하게 만들기 때문에 접근성 측면에서도 안좋습니다.

p {
  font-size: 16px;
}

relative unit

ex) rem, em, %, vw, vh
어떤 기준에 의해 상대적으로 값이 정해지는 단위들을 살펴보고 그들의 기준과 동작원리를 먼저 익혀봅시다.

Percentage units

  • 기준: 브라우저가 정한 기본 글꼴 크기
  • 작용: 퍼센트 비율

대부분의 브라우저가 base font size를 16px로 정의하므로, 일반적으로 100%는 16px입니다.
따라서 루트 엘리먼트에서 퍼센트로 정의를 해주면 접근성을 취하면서 상대적인 값으로 코딩이 가능해집니다.

html {
  font-size: 100%; /* 16px */
}

Em units

  • 기준: 현재 글자 크기. 즉, 자신에게 상속됐던 글자 크기. 따라서 부모의 글자 크기겠죠.
  • 작용: 배수

상대적으로 작용하는 점은 매우 훌륭하지만, font-size를 전부 em으로 설계하면 중첩될수록 계산이 너무 복잡해지는 문제가 있습니다.

.p-wrapper {
  font-size: 10px;
}
.p {
  font-size: 2em; /* 20px */
}

Rem units

  • 기준: html의 글자 크기
  • 작용: 배수

em의 기준점이 많이 바뀌는 단점을 보완하여 계산이 편합니다.

Viewport units

  • 기준: 뷰포트의 가로와 세로 값
  • 작용: 퍼센트

정말 의미적으로 완벽한 반응형 폰트이지만, 브라우저의 크기에만 반응하므로 그냥 쓰기엔 글씨가 엄청 커지거나 작아질 수 있고,
브라우저의 기본 글꼴 크기에 접근하지 못하므로 글씨 크기를 변경할 수 없어집니다.

반응형 글꼴 체계 만들기

글씨 크기도 반응형으로 만들어서 완벽한 반응형을 만들어 봅시다!!

반응형 글씨 계산 공식

  • 제일 왼쪽 영역: 최소값을 더해줌으로써 최소값을 보장합니다.
  • 제일 오른쪽 영역: 최대값에서 최소값을 뺀 값을 곱하면 최대값이 보장됩니다.
  • 가운데 영역: 오른쪽 영역을 곱한 값이 최대값으로 귀결되려면 이 영역은 1보다 적어야 겠네요. 최대의 변동폭 분의 현재 변동폭을 비율로 계산하여 비율을 만들어냅니다!

최솟값과 최대값 사이의 비율에 맞는 값을 구했으니 미디어쿼리로 최소값과 최대값의 한계만 정해주면 반응형 글꼴을 완성할 수 있습니다!

h1 {
    font-size: 2.25rem; // 36px
}

@media (min-width: 414px){
  h1 {
    font-size: calc(2.25rem + (((100vw - 20rem) / (90 - 20))) * (4.75 - 2.25)); // fluidly scale
  }
}

@media (min-width: 1440px){
  h1 {
    font-size: 4.75rem; // 76px
  }
}

이건 scss로 계산값을 자동화 한 방법입니다.

@mixin calc-font-size($min-vw, $max-vw, $min-font-size, $max-font-size){
    font-size: calc(#{$min-font-size}rem + ((100vw - #{$min-vw}rem) / (#{$max-vw} - #{$min-vw})) * (#{$max-font-size} - #{$min-font-size}));
}

h1 {
  font-size: 2.25rem;
}

@media (min-width: 414px){
  h1 {
    @include calc-font-size(25.875, 90, 2.25, 4.75);
  }

@media (min-width: 1440px){
  h1 {
    font-size: 4.75rem;
  }
}

자 이제 마지막 단계만 남았습니다.
지금까지의 방법만으로도 훌륭하지만 rem을 좀 더 계산하기 편하게 바꾸어 봅시다.
보통 브라우저가 정한 기본 글꼴 크기는 16px입니다. 웹에서 보기 편한 사이즈로 설정되어 있죠.
그런데 16은 우리가 쉽게 계산하기 어려운 값입니다. 쉽게 10px로 하면 정말 편할텐데 말이죠!

단순히 html에 10px로 값을 조정해놓고 해당 요소에는 rem단위를 쓸 수도 있지만 그렇게되면 유저가 글꼴의 크기를 조절할 수 없습니다.
고정값인 px로 설정해 놓았기 때문이죠.

브라우저의 base font size에 접근 가능한 것은 %였으니, %를 사용해 봅시다.

html {
  font-size: 62.5%; /* 10px */
}
body {
  font-size: 1.4rem;
}

이 것도 비율을 이용한 계산인데요, 기본 크기인 16px이 100%일 때 10px은 62.5%가 됩니다.
기본이 10px이면 그냥 적용하는 글씨가 너무 작으니 body에 default 값을 추가로 적어줘도 되지만 어차피 다 반응형으로 계산될 폰트라면 의미가 없기도 하네요.


수정이력
2020.07.01

profile
정리하는 개발자

1개의 댓글

comment-user-thumbnail
2020년 6월 26일

많은 도움이 되었습니다. 감사합니다!

답글 달기