Web/[JS] FrontEnd

Responsive Web

ihl 2021. 5. 6. 20:21

다양한 웹 환경

  데스크탑 뿐만 아니라 모바일, 태블릿 등의 기기가 보편화 되면서 사람들은 웹 사이트를 각 기기에 따라 보기 편한 형태로 제공하는 반응형 웹의 필요성을 느끼게 되었다.

 

1. 적응형 웹과 반응형 웹 

m.naver.com

  모바일 환경에서 네이버에 접속하면 주소가 m.naver이다. 네이버 홈화면은 적응형 웹이다. 적응형 웹이란 클라이언트의 기기 정보를 미리 받아 조건 별로 다른 리소스를 보여주는 것이다. 즉, 데스크탑, 모바일, 태블릿 기기마다 별도의 템플릿과 리소스를 작성하는 것이다. 다소 번거롭지만 구축 해놓으면 해당 기기에 맞는 콘텐츠만 다운로드 받으므로 반응형 웹에 비해 로드 속도가 빠르다.

 

  반응형 웹은 기기의 조건에 상관없이 같은 리소스를 보여주되 CSS를 이용하여 브라우저 크기에 따라 레이아웃이 달라지는 형태이다. 예를들어 메인 페이지의 로고의 width를 80%로 잡으면 기기의 너비에 따라 다른 크기의 로고가 보여질 것이다. 하나의 템플릿/URL으로 모든 기기에 대응할 수 있지만, 모바일에서 접속할 때도 데스크탑을 위한 CSS를 모두 받아야하므로 적응형에 비해 로딩 속도가 느리다.

 

2. 뷰포트

viewport 적용유무에 따른 화면

  반응형 웹을 만들기 위해선 먼저 페이지가 기기에 따라 크기와 배율이 조절된다는 것을 브라우저에 알려야한다. 이 역할을 하는 것이 viewport 태그이다. 뷰포트란 화면에 보이는 영역이다. PC의 경우 브라우저 크기 변화에 따라 뷰포트도 변경된다. 모바일의 경우 일반적으로(멀티뷰 제외) 화면 크기를 조절할 수 없으므로 뷰포트가 고정되어 있다.

 

  모바일은 데스크탑보다 화면이 작기 때문에 화면보다 큰 웹페이지을 보여주기 위해 웹 페이지 너비/높이 자체를 줄여서 보여주는 것이 기본 정책이다. 그런데 작은 모바일 화면에서 축소된 웹페이지 화면을 보게되면 위 그림처럼 레이아웃비율도 맞지 않고 컨텐츠 가독성도 떨어진다.

 

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

  뷰포트는 문서의 메타데이터를 저장하는 head 태그 내에 포함되며, content 속성에 값을 추가하여 설정한다. 뷰포트에 들어갈 수 있는 값은 다음과 같다.

  • width: 페이지 너비
    • width=device-width: 페이지 너비를 기기의 너비와 동일하게(initial-scale=1.0과 동일)
  • height: 페이지 높이
    • height=device-height: 페이지 너비를 기기의 높이와 동일하게
    • width/height 설정 없이 initial-scale설정 -> width, height가 기본 값(980px, 1091px)을 갖는다.
  • initial-scale: 초기 화면 배율(0-10)
    • initial-scale=1.0: 초기 화면을 1:1비율로 표시(모바일에서 축소된 화면으로 보여지지 않게 한다)
    • initial-scale 설정 없이 width/height 설정 -> 축소된 웹의 전체화면이 보여진다.
  • minimum-scale: 기기에서 줌 아웃 시 줄어들 수 있는 최소 비율 값(1이면 축소가 안됨)
  • maximum-scale: 기기에서 줌 인 시 커질 수 있는 최대 비율 값(1이면 확대가 안됨)
  • user-scalable: 유저가 줌 인/아웃 가능한지 여부
    • user-scalable=no: 유저가 줌 인/아웃 불가능

3. 미디어 쿼리

[only or not]@media [미디어타입][and or ,](조건문){실행문}

  미디어 쿼리란 웹에 접속한 기기의 환경을 감지하여 CSS를 변경하는 기술로 위와 같은 포맷을 갖고있으며 보통 .css 파일에 사용한다.

 

@media screen and (max-width: 768px) {
  body { background-color: green; }
}

@media (min-width:320px), max(width: 768px) {
  body { background-color: blue; }
}

  첫 번째 미디어 쿼리는 미디어가 screen이고 width가 768px 이하일 때 background-color를 green으로 바꾸는 내용이다. 두 번째 미디어 쿼리는 너비가 320px 이상 768px 이하일 때 background-color를 blue로 바꾼다.

 

  미디어 쿼리에 사용할 수 있는 키워드는 width/height, device-width/height(기기 자체의 너비/높이), orientation(기기의 화면 방향), aspect-ratio(화면비율) 등이 존재한다. 미디어 타입은 all, screen(컴퓨터/스마트기기), print 등이 존재한다.

 

/*good case*/
/* 공통 + 모바일용 CSS */
@media all (min-width: 768px) { /* 태블릿용 CSS */ }
@media all (min-width: 960px) { /* 데스크탑용 CSS */ }

/*bad case*/
/* 공통 + 데스크탑용 CSS */
@media all (min-width: 768px) { /* 태블릿용 CSS */ }
@media all (min-width: 360px) { /* 모바일 CSS */ }

  미디어 쿼리를 작성할 때는 CSS가 위에서 아래로의 흐름을 갖는 것에 주의하여야한다. 위 코드의 첫 번째 예시는 원하는 대로 CSS가 적용되지만, 두 번째 예시는 적용되지 않는다. 1280px 데스크탑이 두 번째 코드를 보면 먼저 공통 + 데스크탑용 CSS를 적용한 후 768px 이상 태블릿용CSS가 적용되고, 360px 이상 모바일 CSS도 적용되어 결국 모바일용 CSS가 적용되어있을 것이다.

 

$mobile-size: 360px;
@mixin mobile { /*미디어쿼리 믹스인*/
  @media screen and (max-width: #{$mobile-size}) {
    @content;
  }
}

@include mobile { /*미디어쿼리 믹스인 사용하기*/
  #searchbar {
    visibility: hidden;
  }
}

  SCSS를 사용하는 경우 위와 같이 믹스인으로 미디어 쿼리를 작성해놓고 사용할 수 있다.

4. 반응형 JavaScript

const mediqQL = window.matchMedia("screen and (min-width: 768px)");

if(mediaQL.matches) { console.log("768px 이상 화면"); }
else { console.log("768px 이하 화면"); }

  JavaScript 코드에서도 window.mediaMatch()를 이용하여 화면 크기를 감지할 수 있다. 위의 코드는 화면 크기에 따라 다른 콘솔로그를 출력하는 코드이다. mediaMatch()의 리턴 값인 mediaQL에 이벤트 리스너를 달 수도 있다.

 

6. 반응형 React

import React from 'react';
import { useMediaQuery } from 'react-responsive';

const Menu: React.FC = () => { 
  const isMobile = useMediaQuery({
    query: '(max-width: 360px)'
  });

  return (
    <div className="menu-container">
      {isMobile?
      	<MobileMenu/> :
        <DesktopMenu/>
      }
    </div>
  );
};

  React로 개발하다보면 모바일인지 데스크탑인지에 따라 렌더링 하거나 하지 않아야 하는 컴포넌트들이 생길 수 있다. 이 때 react-responsive 모듈이 제공하는 useMediaQuery를 사용하면 위와 같이 간단하게 구현할 수 있다.

 


developers.google.com/search/mobile-sites/mobile-seo/responsive-design

www.npmjs.com/package/react-responsive