Responsive Layout

divedeepp·2022년 2월 22일
0

CSS3

목록 보기
19/21

앞 선 챕터에서 살펴본 레이아웃에는 사실 몇가지 문제가 있는데, 이를 해결할 방법이 바로 Responsive Web Design이다.

먼저 어떤 문제가 있는지 살펴보자.

화면폭을 좁히면 아래 그림과 같이 화면이 망가지는데 HTML element에 고정폭을 지정하여 가로 스크롤을 발생시키지 않으면 해결이 어렵다.

그리고 모바일과 같이 작은 해상도의 디바이스에서 접근했을 때 화면이 너무 작아져 가독성이 떨어진다.


Responsive Web Design 개요

사용자가 어떤 디바이스로 웹사이트를 방문할지 알 수 없다. 레이아웃은 방문자의 화면 해상도를 고려해야 한다. 가로폭이 너무 큰 레이아웃을 작성하면 작은 해상도 모니터로 방문했을 때, 가로 스크롤이 생겨서 사용이 불편할 수도 있다.

또한, 스마트폰이나 태블릿 등 모바일 기기는 화면이 작기 때문에 가독성에 더욱 신경써야 한다. 보통 웹사이트가 축소되어 가로 스크롤 없이 컨텐츠를 볼 수 있으나 글자가 너무 작아지기 때문이다. 각각 데스크탑용, 태블릿용, 모바일용 웹사이트를 별도로 구축할 수도 있지만 One Source Multi Use의 관점에서 올바른 해결책은 아니다.

이러한 문제를 해결하는 방법 중의 하나가 Responsive Web Design이다. 화면 해상도에 따라 가로폭이나 배치를 변경하여 가독성을 높이는 것이다. 즉, 하나의 웹사이트를 구축하여 다양한 디바이스의 화면 해상도에 최적화된 웹사이트를 제공하는 것이다.

또한, 최근 모바일 웹페이지는 대부분 애플리케이션의 형태로 진화하고 있어 앱인지 웹인지 구분이 어려울 정도이다. HTML5/CSS3/JavaScript 만으로 네이티브 앱과 차이를 느낄 수 없는 앱을 만들 수 있다.

<meta> tag에 viewport

viewport란 웹페이지의 가시영역을 의미한다.

viewport는 디바이스에 따라 차이가 있다. 예를 들어, 모바일 브라우저는 주화면이 세로 화면이고 윈도우 resize가 불가하며 화면 터치를 사용하는 등 데스크탑 브라우저와 구성이나 형태가 다르다. 또한 모바일의 화면은 데스크탑 화면보다 훨씬 작으므로 데스크탑용 웹페이지를 그대로 모바일에 출력하면 가독성이 현저히 나빠진다.

따라서, vieport를 이용해서 디바이스의 특성과 디바이스의 화면 크기를 고려하여 각종 디바이스 사용자에게 최적화된 웹페이지를 제공할 수 있다.

<meta> tag는 브라우저 혹은 SEO를 위해 검색엔진에게 메타데이터를 전달하기 위해 사용된다. 그 중, viewport <meta> tag는 브라우저의 화면 설정과 관련된 정보를 제공한다.

<meta> tag에 설정할 수 있는 property는 다음과 같다. 크기는 px 단위를 사용하며, 단위 표현은 생략된다. 그리고 다수의 property를 지정할 때는 쉼표로 구분한다.

아래 예제는 가장 일반적인 viewport 설정이다. 가로폭을 디바이스의 가로폭에 맞추고, 초기 화면 배율을 100%로 설정하는 것을 의미한다.

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

일반적으로 viewport meta tag는 모바일 디바이스에서만 적용된다.

@media

서로 다른 미디어 타입(print, screen)에 따라 각각의 스타일을 지정하는 것이 가능하다. 다음은 일반 화면(screen)과 인쇄장치(print) 별로 서로 다른 스타일을 지정하는 예이다.

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    @media screen {
      * { color: red; }
    }
    @media print {
      * { color: blue; }
    }
  </style>
</head>
<body>
  <h1>@media practice</h1>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>

@media은 반응형 웹 디자인에 사용되는 핵심 기술이라 할 수 있다.

@media 를 사용하여 미디어 별로 스타일을 지정하는 것을 Media Query라 한다. 디바이스를 지정하는 것 뿐만 아니라 디바이스의 크기나 비율까지 구분할 수 있다.

다음은 Media Query의 문법이다.

@media not|only mediatype and (expressions) {
  CSS-Code;
}
@media screen and (min-width: 480px) {
  body {
    background-color: lightgreen;
  }
}

아래의 표는 Media Query의 표현식에서 사용할 수 있는 property이다. orientation을 제외한 모든 property는 min 혹은 max 접두사를 사용할 수 있다.

일반적으로 반응형 웹 디자인은 viewport 너비(width property)를 기준으로 한다. viewport의 width property를 이용하여 viewport 너비에 따라 반응하는 범위(breakpoint)를 지정할 수 있다.

/*==========  Mobile First Method  ==========*/
/* All Device */

/* Custom, iPhone Retina : 320px ~ */
@media only screen and (min-width : 320px) {

}
/* Extra Small Devices, Phones : 480px ~ */
@media only screen and (min-width : 480px) {

}
/* Small Devices, Tablets : 768px ~ */
@media only screen and (min-width : 768px) {

}
/* Medium Devices, Desktops : 992px ~ */
@media only screen and (min-width : 992px) {

}
/* Large Devices, Wide Screens : 1200px ~ */
@media only screen and (min-width : 1200px) {

}

/*==========  Non-Mobile First Method  ==========*/
/* All Device */

/* Large Devices, Wide Screens : ~ 1200px */
@media only screen and (max-width : 1200px) {

}
/* Medium Devices, Desktops : ~ 992px */
@media only screen and (max-width : 992px) {

}
/* Small Devices, Tablets : ~ 768px */
@media only screen and (max-width : 768px) {

}
/* Extra Small Devices, Phones : ~ 480px */
@media only screen and (max-width : 480px) {

}
/* Custom, iPhone Retina : ~ 320px */
@media only screen and (max-width : 320px) {

}

다음은 임의로 해상도를 3단계로 구분하여 범위를 지정한 예제이다.

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    /* 801px ~ */
    * { color: black; }
    /* ~ 800px */
    @media screen and (max-width: 800px) {
      * { color: blue; }
    }
    /* ~ 480px */
    @media screen and (max-width: 480px) {
      * { color: red; }
    }
  </style>
</head>
<body>
  <h1>@media practice</h1>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>

다음은 화면이 세로일 때, 가로일 때를 구분하는 예제이다. 주의할 점은 데스크탑은 언제나 가로화면이기 때문에 device-width로 스마트폰의 해상도를 지정하지 않으면 데스크탑에서도 가로화면일 때 스타일이 적용되는 문제가 발생한다.

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    /* 세로  */
    * { color: black; }
    /* 가로 */
    /* Desktop의 화면은 가로화면(landscape)이므로 아래 rule이 적용된다. */
    /*
    @media screen and (orientation: landscape) {
      { color: blue; }
    }
    */

    /* Landscape */
    @media screen
      /* 디바이스가 모바일일때(device-width 0 ~ 768px) */
      and (max-device-width: 760px)
      /* 가로 */
      and (orientation: landscape) {
      * { color: blue; }
    }
  </style>
</head>
<body>
  <h1>@media practice: orientation</h1>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>

이제까지의 내용을 바탕으로 레이아웃 챕터에서 만들어본 웹페이지를 Responsive Web Design에 맞추어 수정해보자.


Responsive Navigation Bar

디바이스의 해상도에 따라 반응할 수 있도록 viewport meta tag와 media query를 추가한다.

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    /* Media Query */
    /* for Desktop: 801px ~ */

    /* for tablet: ~ 800px */
    @media screen and (max-width: 800px) {

    }
    /* for smartphone: ~ 480px */
    @media screen and (max-width: 480px) {

    }
  </style>
</head>
...

스마트폰, 태블릿, 데스크탑 총 3 단계 지점으로 정의했다. Non Mobile First Method로 정의하였기 때문에, media query로 정의하지 않은 스타일은 데스크탑을 위한 코드가 된다.

예를 들어, max-width: 800px로 정의한 것은 화면 크기가 800px 이하인 디바이스를 위한 query란 의미가 된다. 따라서, 해당 지점에 정의되는 스타일은 화면 크기가 800px 이하인 디바이스에서 웹사이트가 실행될 때 표시된다.

Media Query에도 CSS Cascading Order가 적용되므로 기술되는 순서가 중요하며, 나중에 선언된 스타일이 우선 적용된다. 만일 스마트폰용 스타일을 태블릿용 스타일보다 먼저 기술하면 최종적으로 태블릿용 스타일이 적용된다. 따라서, Non Mobile First 방식의 경우, max-width property의 값이 큰 것부터 기술해야 한다.

/* Media Query */
/* for Desktop: 801px ~ */

/* for smartphone: ~ 480px */
/*
Media Query는 기술 순서에 의미가 있다.
만일 스마트폰용 스타일을 태블릿용 스타일보다 먼저 기술하면 최종적으로 태블릿용 스타일이 적용된다.
Non Mobile First Method의 경우, max-width의 값이 큰 것부터 기술하여 한다.
*/
@media screen and (max-width: 480px) {

}

/* for tablet: ~ 800px */
@media screen and (max-width: 800px) {

}

일반적으로 Mobile-first 방식은 해상도가 작은 순서로, Non Mobile-first 방식은 해상도가 큰 순서로 기술한다. 위의 코드는 Mobile-first 방식이다.

Responsive Navigation Bar - Tablet

데스크탑 레이아웃에서 화면이 작아질 때 header navigation bar가 header 영역 아래로 내려오는 현상이 발생했다. 이를 보완하기 위해 다음과 같이 태블릿에서의 레이아웃을 정의한다.

viewport width가 800px 이하가 되면 header 영역을 2단(logo 영역과 navigation bar 영역)으로 구분하기 위하여 header 영역의 높이를 현재(60px)의 2배로 넓힌다. 그리고 logo 이미지와 navigation bar를 중앙 정렬한다.

@media screen and (max-width: 800px) {
  header {
    height: 120px;
    text-align: center;
  }
}

이 때 aside, section 영역도 header의 height만큼 내려가야 한다.

@media screen and (max-width: 800px) {
  header {
    height: 120px;
    text-align: center;
  }
  #wrap {
    /* margin-top = header height */
    margin-top: 120px;
  }
  aside {
    top: 120px;
  }
}

가로로 나란히 정렬되어 있던 logo 이미지와 navigation bar를 상단과 하단으로 분리 배치하기 위하여 navigation bar의 float: right; property를 해제 한다. 그러면 navigation bar는 block property를 가지게 되어 logo 이미지의 아래 영역으로 내려가게 된다.

@media screen and (max-width: 800px) {
  header {
    height: 120px;
    text-align: center;
  }
  nav {
    float: none;
    /*margin-right: 0;*/
  }
  #wrap {
    /* margin-top = header height */
    margin-top: 120px;
  }
  aside {
    top: 120px;
  }
}

Responsive Navigation Bar - Smartphone

태블릿 레이아웃에서는 header 영역을 2단으로 분리하여 navigation bar는 header 하단 영역에 배치하였다. 하지만 스마트폰의 viewport width는 가로로 나란히 정렬되어 있는 navigation bar를 모두 담기에는 너무 좁다. 따라서 다음과 같이 스마트폰 레이아웃을 정의한다.

우측 navigation icon을 클릭하면 navigation bar가 수직 정렬되어 화면에 나타나도록 한다. 한번 더 클릭하면 화면에서 사라지도록 한다. 이 때 navigation icon에 animation 효과를 부여한다.

<nav> element 내에 클릭할 수 있는 navigation icon을 만들기 위한 <input><label> tag를 추가한다. <label> tag의 for property 값과 <input> tag의 id property 값이 일치해야 한다.

<nav>
  <input class="nav-toggle" id="nav-toggle" type="checkbox">
  <label class="navicon" for="nav-toggle"><span class="navicon-bar"></span></label>
  <ul class="nav-items">
    <li><a href="#home">Home</a></li>
...

위의 코드는 checkbox의 default 스타일을 사용하지 않고, 커스텀 navigation icon을 사용하기 위한 방법이다.

<input> element의 id property 값과 <label> element의 for property 값을 일치시켜 연동하면 <label> element를 클릭해도 <input> element가 클릭된다.

이것을 이용해서 <label> element의 content를 커스텀 navigation icon으로 만들어 주고, <input> element의 기본 외관을 비표시하는 방법이다.

그럼, navigation icon을 만들어 보자.

navigation icon은 <input> element와 연동된<label> element를 사용했다. 즉, navigation icon을 클릭하면 <input> tag도 checked 상태가 된다.

navigation icon의 스타일은 다음과 같이 정의한다.

.navicon {
  cursor: pointer;
  height: 60px;
  padding: 28px 15px;
  position: absolute;
  top: 0; right: 0;
}

navigation icon은 header 우측에 배치되어야 하므로 position: absolute; 를 지정한다. 이 경우에는 부모 element가 static이므로, navigation icon은 <body> element를 기준으로 위치한다. 따라서, 부모 element에 별도의 처리가 필요없다.

다음은 <label> tag 내의 <span> tag의 스타일을 정의한다. <span> tag는 navigation icon의 막대 3개(클릭 시에는 X 표시)를 표현하기 위해 정의했다.

.navicon-bar {
  display: block;
  width: 20px;
  height: 3px;
  background-color: #333;
}

위 그림과 같이 navigation icon의 막대 1개가 표시된다.

pseudo-element selector를 사용하여 navigation icon의 내부 막대 앞 뒤 공간에 막대를 추가한다.

.navicon-bar::before,
.navicon-bar::after {
  background-color: #333;
  content: "";
  display: block;
  height: 100%;
  width: 100%;
  position: absolute;
}
.navicon-bar::before {
  top: -7px;
}
.navicon-bar::after {
  top: 7px;
}

position: absolute;를 지정했으므로, 부모 element인 <span> element(.navigation-bar)에 position: relative;를 추가한다.

.navicon-bar {
  background-color: #333;
  display: block;
  position: relative;
  width: 20px;
  height: 3px;
}

아직 navigation icon을 클릭해도 아무런 반응이 없다. navigation icon을 클릭하면 클리되었음을 사용자가 확인할 수 있도록 navigation icon의 스타일을 변화시킨다.

<input> tag의 pseudo class selector인 :checked 를 이용하여 클릭되었을 때(checked)와 그렇지 않을 때를 구분할 수 있다. 먼저 중간에 위치한 막대를 투명화시키고, 상하 막대를 45도 회전시킨다. 이 때 위치가 틀어지므로 top: 0; 로 보정한다. 이제 클릭되었을 때, X 표시로 바뀐다.

.nav-toggle:checked ~ .navicon > .navicon-bar {
  background: transparent;
}
.nav-toggle:checked ~ .navicon > .navicon-bar::before {
  transform: rotate(45deg);
  top: 0;
}
.nav-toggle:checked ~ .navicon > .navicon-bar::after {
  transform: rotate(-45deg);
  top: 0;
}

navigation icon에 transition 효과를 부여하여 좀 더 부드럽게 움직이도록 한다. transition property는 property, duration, delay 순으로 정의한다.

.navicon-bar {
  background-color: #333;
  display: block;
  position: relative;
  transition: background-color .2s ease-out;
  width: 20px;
  height: 3px;
}
.navicon-bar::before,
.navicon-bar::after {
  background-color: #333;
  content: "";
  display: block;
  height: 100%;
  width: 100%;
  position: absolute;
  transition: all .2s ease-out;
}

근데 navigation icon을 클릭하면 의도하지 않게 이미지가 선택되는 현상이 발생할 수 있다.

이것은 navigation icon이 텍스트이기 때문에 발생하는 문제이다. 이 문제는 텍스트 선택을 차단하는 방법인 user-select: none; property를 지정하여 회피할 수 있다. 현재 CSS 사양에 포함되어있지 않으므로 vendor prefix를 사용한다.

.navicon {
  cursor: pointer;
  height: 60px;
  padding: 28px 15px;
  position: absolute;
  top: 0; right: 0;

  -webkit-user-select: none;  /* Chrome all / Safari all */
  -moz-user-select: none;     /* Firefox all */
  -ms-user-select: none;      /* IE 10+ */
  user-select: none;          /* Likely future */
}

navigation icon과 <input> tag는 스마트폰 이외의 경우, 화면에 표시되면 안된다. 따라서 display: none; 으로 화면에 표시되지 않도록 한다. Cascading order를 고려해서 가장 마지막에 정의하는 것이 안전하다. 일반적으로 media query를 가장 마지막에 정의하므로 media query 정의부 앞에 위치시킨다.

.nav-toggle {
  display: none;
}
.navicon {
  display: none;
}

태블릿용 레이아웃에서 header height을 2배로 하였으므로, 모바일용 레이아웃을 위해 다시 60px로 되돌린다.

@media screen and (max-width: 480px) {
  header {
    height: 60px;
  }
}

스마트폰 레이아웃에서는 navigation bar가 초기 상태에서 비표시되어야 한다. 그리고 navigation icon은 표시되어야 한다. 아직 navigation icon을 완성하지 않았으므로 표시되지 않는다.

@media screen and (max-width: 480px) {
  header {
    height: 60px;
  }
  .nav-items {
    display: none;
  }
  .navicon {
    display: block;
  }
}

또 콘텐츠 영역이 아직 테블릿 레이아웃에 맞추어 아래로 내려가 있다. 따라서 header 영역 바로 아래까지 끌어 올린다.

@media screen and (max-width: 480px) {
  /*...*/
  #wrap {
    /* margin-top = header height */
    margin-top: 60px;
  }
  aside {
    top: 60px;
  }
  /*...*/
}

마지막으로 navigation icon을 클릭하면 navigation item이 표시되도록 한다.

@media screen and (max-width: 480px) {
  ...

  .nav-toggle:checked ~ .nav-items {
    display: block;
    width: 100%;
    background-color: #fff;
    box-shadow: 0 2px 2px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(0, 0, 0, 0.05);
  }
  .nav-items > li  {
    display: block;
  }
  .nav-items > li > a {
    line-height: 50px;
  }
}

Responsive Section / Aside / Footer

현재 article은 레이아웃에 상관없이 1행에 1개씩 배치되었다. responsive web design의 효과를 좀 더 체감하기 위해 1행에 2열로 배치한다.

article을 2열로 배치하기 위해서 width 값을 지정해야 한다. %로 width 값을 지정해서 viewport에 상대적인 너비를 갖도록 한다. 이 때, margin도 %로 지정한다. 그리고 float: left; 를 지정해서 2열로 정렬되도록 한다.

article {
  width: 48.5%;
  margin: 1%;
  padding: 25px;
  background-color: white;
  float: left;
}

짝수번 째 배치되는 article의 좌측 margin과 3번째부터 등장하는 article의 위측 margin을 0으로 하여 가운데 margin이 2배가 되는 것을 방지한다.

article:nth-of-type(2n) {
  margin-left: 0;
}
article:nth-of-type(n+3) {
  margin-top: 0;
}

태블릿 레이아웃을 작성한다. 800px 이하로 화면이 작아지면 2열 배치되어 있던 article을 1열로 배치한다.

@media screen and (max-width: 800px) {
  ...
  article {
    width: inherit;
    display: block;
    margin: 10px;
    float: none;
  }
  article:nth-of-type(2n) {
    margin: 10px;
  }
  article:nth-of-type(n+2) {
    margin-top: 0;
  }
}

모바일 레이아웃을 작성한다. 480px 이하로 화면이 작아지면 고정 배치되어 있던 aside를 article 위로 올려 배치한다.

@media screen and (max-width: 480px) {
  /*...*/
  aside {
    top: 60px;
    position: static;
    width: 100%;
    padding: 5px 0;
  }
  /* aside navigation */
  aside > ul {
    width: 100%;
  }
  aside > h1 {
    padding: 5px 0 10px 20px;
    color: #fff;
  }
  section {
    float: none;
    margin-left: 0;
  }
  /*...*/
}

최종 완성된 코드는 아래와 같다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <style>
      /* Simple Reset CSS */
      * {
        margin: 0; padding: 0;
        box-sizing: border-box;
      }
      body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        color: #58666e;
        background-color: #f0f3f4;
        -webkit-font-smoothing: antialiased;
        -webkit-text-size-adjus: 100%;  /* iphone font size 변경 방지 */
      }
      li { list-style: none; }
      a { text-decoration: none; }
      h1, h2, h3, h4, h5, h6, p {
        margin: 10px 5px;
      }
      h1 { font-size: 1.8em; }

      #wrap {
        width: 100%;
        /* margin-top = header height */
        margin-top: 60px;
      }

      /* Navigation bar */
      header {
        /* for sticky header */
        position: fixed;
        top: 0;

        width: 100%;
        height: 60px;
        z-index: 2000;
        background-color: #fff;
        box-shadow: 0 2px 2px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(0, 0, 0, 0.05);
      }
      .logo {
        display: inline-block;
        height: 36px;
        margin: 12px 0 12px 25px;
      }
      .logo > img { height: 36px; }
      nav {
        float: right;
      }
      .nav-items {
        margin-right: 20px;
      }
      .nav-items > li {
        display: inline-block; /* 가로정렬 */
      }
      .nav-items > li > a {
        line-height: 60px; /* for Vertical Centering */
        padding: 0 30px;   /* nav item간 간격 */
        color: rgba(0,0,0,0.4);
      }
      .nav-items > li > a:hover {
        color: rgba(0,0,0,0.8);
      }

      /* navigation icon for Mobile Layout */
      .navicon {
        cursor: pointer;
        height: 60px;
        padding: 28px 15px;
        position: absolute;
        top: 0; right: 0;

        -webkit-user-select: none;  /* Chrome all / Safari all */
        -moz-user-select: none;     /* Firefox all */
        -ms-user-select: none;      /* IE 10+ */
        user-select: none;          /* Likely future */
      }
      /* nav icon의 내부 막대 */
      .navicon-bar {
        background-color: #333;
        display: block;
        position: relative;
        /* navigation icon animation */
        transition: background-color .2s ease-out;
        width: 20px;
        height: 3px;
      }
      .navicon-bar::before,
      .navicon-bar::after {
        background-color: #333;
        content: "";
        display: block;
        height: 100%;
        position: absolute;
        /* navigation icon animation */
        transition: all .2s ease-out;
        width: 100%;
      }
      .navicon-bar::before {
        top: -7px;
      }
      .navicon-bar::after {
        top: 7px;
      }
      /* toggle navigation icon */
      .nav-toggle:checked ~ .navicon > .navicon-bar {
        background: transparent;
      }
      .nav-toggle:checked ~ .navicon > .navicon-bar::before {
        transform: rotate(45deg);
        top: 0;
      }
      .nav-toggle:checked ~ .navicon > .navicon-bar::after {
        transform: rotate(-45deg);
        top: 0;
      }

      /* contents */
      /* clearfix */
      #content-wrap:after {
        content: "";
        display: block;
        clear: both;
      }
      aside {
        /* for fixed side bar */
        position: fixed;
        top: 60px;
        bottom: 0;

        width: 200px;  /* 너비 고정 */
        padding-top: 25px;
        background-color: #333;
      }
      /* aside navigation */
      aside > ul {
        width: 200px;
      }
      aside > ul > li > a {
        display: block;
        color: #fff;
        padding: 10px 0 10px 20px;
      }
      aside > ul > li > a.active {
        background-color: #4CAF50;
      }
      aside > ul > li > a:hover:not(.active) {
        background-color: #555;
      }
      aside > h1 {
        padding: 20px 0 20px 20px;
        color: #fff;
      }
      /* Section */
      section {
        float: right;
        margin-left: 200px;  /*aside width*/
      }
      article {
        width: 48.5%;
        margin: 1%;
        padding: 25px;
        background-color: white;
        float: left;
      }
      article:nth-of-type(2n) {
        margin-left: 0;
      }
      article:nth-of-type(n+3) {
        margin-top: 0;
      }
      /* footer */
      footer {
        /* footer를 aside위에 올리기 위해 사용(부유객체) */
        position: absolute;
        height: 60px;
        width: 100%;
        padding: 0 25px;
        line-height: 60px;
        color: #8a8c8f;
        border-top: 1px solid #dee5e7;
        background-color: #f2f2f2;
      }

      .nav-toggle {
        display: none;
      }
      .navicon {
        display: none;
      }

      /* Media Query */
      /* for tablet: ~ 800px */
      @media screen and (max-width: 800px) {
        header {
          height: 120px;
          text-align: center;
        }
        nav {
          float: none;
          margin-right: 0;
        }
        #wrap {
          /* margin-top = header height */
          margin-top: 120px;
        }
        aside {
          top: 120px;
        }

        article {
          width: inherit;
          display: block;
          margin: 10px;
          float: none;
        }
        article:nth-of-type(2n) {
          margin: 10px;
        }
        article:nth-of-type(n+2) {
          margin-top: 0;
        }
      }
      /* for smartphone: ~ 480px */
      @media screen and (max-width: 480px) {
        header {
          height: 60px;
        }
        .nav-items {
          display: none;
        }
        .navicon {
          display: block;
        }
        #wrap {
          /* margin-top = header height */
          margin-top: 60px;
        }
        aside {
          top: 60px;
          position: static;
          width: 100%;
          padding: 5px 0;
        }
        /* aside navigation */
        aside > ul {
          width: 100%;
        }
        aside > h1 {
          padding: 5px 0 10px 20px;
          color: #fff;
        }
        section {
          float: none;
          margin-left: 0;
        }
        /* View navigation item */
        .nav-toggle:checked ~ .nav-items {
          display: block;
          width: 100%;
          background-color: #fff;
          box-shadow: 0 2px 2px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(0, 0, 0, 0.05);
        }
        .nav-items > li  {
          display: block;
        }
        .nav-items > li > a {
          line-height: 50px;
        }
      }
    </style>
  </head>
  <body>
    <div id="wrap">
      <header>
        <a class="logo" href="#home"><img src="https://poiemaweb.com/img/logo.png"></a>
        <nav>
          <input class="nav-toggle" id="nav-toggle" type="checkbox">
          <label class="navicon" for="nav-toggle"><span class="navicon-bar"></span></label>
          <ul class="nav-items">
            <li><a href="#home">Home</a></li>
            <li><a href="#news">News</a></li>
            <li><a href="#contact">Contact</a></li>
            <li><a href="#about">About</a></li>
          </ul>
        </nav>
      </header>

      <div id="content-wrap">
        <aside>
          <h1>Aside</h1>
          <ul>
            <li><a href="#" class="active">London</a></li>
            <li><a href="#">Paris</a></li>
            <li><a href="#">Tokyo</a></li>
            <li><a href="#">Newyork</a></li>
          </ul>
        </aside>
        <section>
          <article id="london">
            <h1>London</h1>
            <p>London is the capital city of England. It is the most populous city in the United Kingdom, with a metropolitan area of over 13 million inhabitants.</p>
            <p>Standing on the River Thames, London has been a major settlement for two millennia,its history going back to its founding by the Romans, who named it Londinium.</p>
            <p>London, also referred to as Greater London, is one of 9 regions of England and the top-level subdivision covering most of the city's metropolis. The small ancient City of London at its core once comprised the whole settlement, but as its urban area grew, the Corporation of London resisted attempts to amalgamate the city with its suburbs, causing "London" to be defined in a number ways for different purposes.</p>
          </article>
          <article id="paris">
            <h1>Paris</h1>
            <p>London is the capital city of England. It is the most populous city in the United Kingdom, with a metropolitan area of over 13 million inhabitants.</p>
            <p>Standing on the River Thames, London has been a major settlement for two millennia,its history going back to its founding by the Romans, who named it Londinium.</p>
            <p>London, also referred to as Greater London, is one of 9 regions of England and the top-level subdivision covering most of the city's metropolis. The small ancient City of London at its core once comprised the whole settlement, but as its urban area grew, the Corporation of London resisted attempts to amalgamate the city with its suburbs, causing "London" to be defined in a number ways for different purposes.</p>
          </article>
          <article id="tokyo">
            <h1>Tokyo</h1>
            <p>London is the capital city of England. It is the most populous city in the United Kingdom, with a metropolitan area of over 13 million inhabitants.</p>
            <p>Standing on the River Thames, London has been a major settlement for two millennia,its history going back to its founding by the Romans, who named it Londinium.</p>
            <p>London, also referred to as Greater London, is one of 9 regions of England and the top-level subdivision covering most of the city's metropolis. The small ancient City of London at its core once comprised the whole settlement, but as its urban area grew, the Corporation of London resisted attempts to amalgamate the city with its suburbs, causing "London" to be defined in a number ways for different purposes.</p>
          </article>
          <article id="newyork">
            <h1>Newyork</h1>
            <p>London is the capital city of England. It is the most populous city in the United Kingdom, with a metropolitan area of over 13 million inhabitants.</p>
            <p>Standing on the River Thames, London has been a major settlement for two millennia,its history going back to its founding by the Romans, who named it Londinium.</p>
            <p>London, also referred to as Greater London, is one of 9 regions of England and the top-level subdivision covering most of the city's metropolis. The small ancient City of London at its core once comprised the whole settlement, but as its urban area grew, the Corporation of London resisted attempts to amalgamate the city with its suburbs, causing "London" to be defined in a number ways for different purposes.</p>
          </article>
        </section>
        <!-- end of content-wrap -->
      </div>
      <footer>© Copyright 2016 ungmo2</footer>
    <!-- end of wrap   -->
    </div>
  </body>
</html>

참고문헌

https://poiemaweb.com/css3-responsive-web-design

profile
더깊이

0개의 댓글