스마트 폰 사용자가 증가하면서 덩달아 급격히 늘고 있는 모바일 브라우징으로 말미암아 다양한 화면 크기에 적절히 대처하려는 시도로 최근 주목받고 있는 웹 디자인 패턴이 Responsive Web Design이다.

CSS3 Media Queries를 써서 서로 다른 디바이스의 화면 크기에 맞춰 적당한 layout을 구현해서 최적화된 브라우징 경험을 제공하려는 것인데, 오래전부터 이곳 블로그도 모바일 기기만을 위한 링크를 따로 제공하고 있지만 별로 만족스럽지는 않았는데, 최근 올라온 CSS3 media queries를 사용한 웹 디자인 소개 글을 참고해서 “반응형 웹 디자인”을 구현해 보았다.

윗글에 설명된 내용 중 중요한 것 몇 가지를 간추리면, 우선 Internet Explorer 8 이하 버전에선 CSS3 media queries를 알아듣지 못하기 때문에 JavaScript의 도움이 필요하다. 대표적으로 아래 두 가지가 있다.

여러 media types와 더불어 min-width와 max-width의 media queries만 쓴다며 크기도 작고 실행속도도 빠른 Respond가 안성맞춤.

다음에 웹 페이지에 포함된 그림은 화면 크기에 맞게 그 크기도 줄어들고 늘어나야 하는데 다음과 같이 지정해준다.

img {
  max-width: 100%;
  height: auto;
}
.ie8 img {
  width: auto; /* for IE8 only */
}

Viewport 정의는 다음과 같이.

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

이미 viewport에 맞게 디자인하였다면 iOS의 Text 크기 자동 조절 기능은 필요 없을 것이다.

html {
  -webkit-text-size-adjust: 100%;
}

덤으로, jQuery plugin인 FitText를 쓰면 header와 같은 곳에 사용된 큼지막한 글자도 화면 크기에 맞게 자동으로 그 크기를 조절해줄 수 있다.

이젠 Responsive Web Design이 선택이 아닌 필수가 되면서, 작은 화면에 보일 ‘content’가 더 돋보이게 되는 순간이다.

기타 참고 사이트:

  • Media Queries – Responsive Web Design을 적용한 사이트를 모아놓았다.
  • 320 and up – A ‘tiny screen first’ boilerplate extension.
  • tinySrc – 작은 화면의 휴대용 기기를 위한 그림 크기 자동 조절/전달 서비스.
  • imgsizer.js – 작은 크기로 축소된 그림이 구 버전 IE(IE7 이하)에서도 흉하게 보이지 않도록 해주는 스크립트.
  • Detect Mobile Browser – Open source mobile phone detection.

현재 제정되고 있는 CSS3 Module 중 CSS Multi-Column Layout Module은 Candidate Recommendation 상태로 거의 권고 마무리 단계에 이르렀으며, 웹 브라우저의 지원 상황도 다른 모듈보단 비교적 양호한 상태이다.

물론, IE나 기타 미지원 브라우저를 위한 간단한 JavaScript pollyfill도 마련되어 있으며, 아무런 조치를 취하지 않아도 원래 내용을 전달하는 데는 별문제가 없어서, 지금 당장 써먹어도 큰 불편은 없다고 할 수 있는데 요놈의 쓰임새는 다음과 같다.

.two-col {
  -webkit-column-count: 2;
  -webkit-column-gap : 20px;
  -webkit-column-rule: 1px dashed #ccc;
  -moz-column-count: 2;
  -moz-column-gap : 20px;
  -moz-column-rule: 1px dashed #ccc;
  column-count: 2;
  column-gap : 20px;
  column-rule: 1px dashed #ccc;
}

이렇듯 그 사용 방식도 명확해서 이해하기도 쉬운데, 브라우저별 구현 방식에서 아직 몇 가지 소소한 차이가 있어서 예상치 못한 부작용을 가져올 수도 있다. Safari와 Firefox의 CSS3 Multi-Column Layout Module 구현 버그(이)란 제목의 글 마저 읽기 →

보통 메뉴를 마크업할 땐 li로 나열해서 float propterty를 줘서 일렬로 늘어트린 후 감싸고 있는 상위 엘르먼트에다 width를 지정하고 margin propterty로 중앙에 위치시키는 기법이 많이 사용된다.

그런데 메뉴가 더 추가되거나 삭제되면 전체 가로 너비를 다시 지정해줘야 하는 문제가 발생하는데, 이런 단점을 보완한 기법이 있는데 바로 display:inlinedisplay:inline-block propterty에 그 해법이 있다.

CSS Wizardry에 소개된 기법으로 마크업과 CSS는 다음과 같다.

마크업:

<ul id="nav">
  <li><a href="/">Home</a></li>
  <li><a href="/about/">About</a></li>
  <li><a href="/work/">Work</a></li>
  <li><a href="/clients/">Clients</a></li>
  <li><a href="/contact/">Contact</a></li>
</ul>

CSS:

#nav{
  border:1px solid #ccc;
  border-width:1px 0;
  list-style:none;
  margin:0;
  padding:0;
  text-align:center;
}
#nav li{
  display:inline;
}
#nav a{
  display:inline-block;
  padding:10px;
}

text-aling:center;로 inline 속성을 갖게 된 li를 중앙 정렬하되 중요한 것은, li에다 display:inline;을 주고 a에는 display:inline-block;을 지정해 주는 것.

일반적으로 그냥 li에 display:inline-block;을 지정해 줄 수도 있지만, IE6-7에선 inline-block을 inline elements에 지정했을 때만 제대로 인식하기 때문에 a elements에 지정하였다.

얼핏 IE에선 inline-block이 말을 잘 듣지 않는다고 들은 것 같아서 이름 그대로 float만 떠올렸는데, IE6-7에서도 inline-block을 제대로만 활용하면 이렇듯 그 효용성은 더 높아질 것이다.

개인적으론 먼저 HTML은 문서의 내용을 제대로 전달해주기 위한 중요한 틀이라고 생각하기 때문에, 항상 마크업을 할 때마다 신중하고 올바른 습관을 들이려 노력하고 있다. 문서를 전달하는 기초 틀만 제대로 짜 놓으면 반 이상 완성된 페이지로 다가섰다고 볼 수 있기 때문이다. 근래 HTML5가 대두하면서 공부해야 할 것도 덩달아 늘어나서 항상 최신 정보를 놓치지 않고 습득하려 노력하고 있다.

CSS를 짤 때의 느낌은 전혀 다른데, 많은 상상력이 필요로 하고 그만큼 디자인 실력과 눈썰미도 받쳐주어야 하는 기술이라고 생각한다. 항상 부족함을 느끼기 때문에 남이 해놓은 멋진 디자인을 보면 모방도 많이 하는 형편이다. 그리고 항상 풀리지 않는 문제로 골치를 앓기도 하는데, 주 요인은 아무래도 IE. 최신 브라우저의 CSS3 지원 상황도 날로 호전되면서 연일 꼼꼼히 챙겨야 할 필요를 느낀다.

마지막으로 JavaScript는 파면 팔수록 난해하지만, 또 신기하기도 하고 페이지에 활력을 불어넣을 수 있는 요술 지팡이 같은 느낌. 예전 조립 장난감의 작은 부품을 붙였다 떼었다 차근차근 조립하고 완성해서 제각기 자기 역할에 맞게 팔다리가 맞물려서 움직이는 모습을 보고 뿌듯해했던 느낌 말이다.

결국은 개인적인 생각에 중요도를 놓고 따지면, HTML > CSS = JavaScript라고 생각하지만, 재미와 매력JavaScript >= HTML > CSS라는 느낌.

꼬리표:

 없음.

Safari extension으로 먼저 나온 바른 말씨Google Chrome 용으로도 배포할 목적으로 개발하면서 부딪혔던 문제로, 대부분의 extension APIs와 그 구조는 서로 닮았기 때문에 코드 이전에는 별다른 어려움은 없었다. 그런데 한 가지 커다란 장벽과 마주쳤으니.

보통 extensions에 의해 페이지에 삽입되는 Content Scripts는 독립적인 sandbox 환경에서 실행되면서 원래 웹 페이지에 존재하는 스크립트와의 간섭을 걱정할 필요 없이 DOM을 만질 수 있게 되는데, 불행히도 Google Chrome extensions에선 iframes 접근이 차단되어 있어서 window.frames 값으로 undefined를 돌려준다. 이 문제는 알려진 버그로, 해결책으로 다음과 같이 Background Page에서 chrome.tabs.executeScript() 명령으로 해당 사이트의 DOM에다 직접 script tag을 생성해서 Chrome의 Sandbox 밖에서 실행되는 스크립트를 삽입해 주는 것이다.

chrome.tabs.executeScript(null, {file: 'scriptInjecting.js'}, scriptInjected);

script tag를 만들고 Sandbox를 탈출해서 실행될 스크립트를 삽입하는 scriptInjecting.js 파일의 내용은 다음과 같다.

(function(doc) {
  var s = doc.createElement('script');
  s.type = 'text/javascript';
  s.src = chrome.extension.getURL("escapedFromChromeSandbox.js");
  var x = doc.getElementsByTagName('script')[0];
  x.parentNode.insertBefore(s, x);
})(document);

이렇게 해서 삽입된 escapedFromChromeSandbox.js 파일에선 iframes의 속 내용을 들여다볼 수 있게 된다.

여기서 얻어진 정보는 가령, hidden input을 만들고 이놈의 value나 title 혹은 data 속성에다가 저장해 놓기만 하면, 나머진 종전처럼 해당 페이지의 DOM 접근이 가능한 Content Scripts에서 이곳에 저장된 정보를 읽고 message passing을 통해 background pages에 전달해주면 된다.

이 밖에도 사소한 것으로, 검사 결과를 보여주는 창을 마우스로 잡아서 이동시킬 수 있도록 하는 기능을 구현하는데, Safari에선 별문제 없던, HTML5의 Drag and Drop 기능을 빌려 쓰려 하였으나 drag시 마우스의 위치 값을 제대로 돌려받지 못하는 문제도 있어서 결국 약간 소모적일 수도 있는 Mouse events를 써야만 했다.

최근 많은 브라우저가 extensions 혹은 add-ons 형태로 사용자 입맛에 맞는 추가 기능을 제공하는 추세이고 또 각 브라우저가 가지고 있는 고유 API와 그 구현 방식도 서로의 차이점이 줄어들고 있기는 하지만, 아직은 개발자에게 혼동을 일으킬 수 있는 미묘한 차이를 보이면서 앞으로 어떤 통합된 개발 환경이 제공되었으면 하는 바람도 가지게 된다.