반응형 웹 개발할 때 레이아웃 px과 이미지 크기

기본

사이트를 반응형으로 개편하면서 한가지 궁금한 점이 생겼습니다. 맥의 레티나 디스플레이나 요새 모바일은 물리적인 화면은 작아도 해상도는 2배-3배인 경우가 있기 때문에 미디어 쿼리의 max-width < 760px 같은 수식이 정말 모바일을 구별 할 수 있을까? 하는 점이죠.

원리는 의의로 간단했습니다. 안드로이드의 dp 개념처럼 웹브라우저도 density 값을 가지고 해상도 / density를 한 값을 미디어 쿼리가 사용합니다. 그래서 해상도가 높아도 모바일과 데스크탑을 구분하는게 가능합니다.

http://uhb.kr/book/wiki/rwd/resolution/

위 사이트에서 브라우저가 계산하는 실제 해상도 크기를 볼 수 있죠.

정리해보면 density가 1인 모니터에서 작업을 할 때 디자인 가이드라인의 px 값은 그대로 사용하고(desity가 다른 환경에서도 동일한 크기로 보여질 테니 말이죠.) 이미지들은 2배-3배 크기가 따로 필요합니다. (아니면 density가 높은 환경에서 이미지를 늘여서 표시해야 하니까요.)

Advertisements

postMessage를 이용한 크로스도메인간 iframe 리사이징

기본

회사에서 외주를 주고 있는 사이트가 변경돼서, <iframe>으로 해당 사이트를 임베드 해야하는 이슈가 있었습니다. <iframe> 해서 추가하는 거야 일도 아닌데 포함시킬려는 페이지의 사이즈에 맞게 사이즈를 조절해 줘야 하더군요.

바꾸기 전에는 같은 도메인이었기 때문에 iframe 안에서 부모쪽의 함수를 호출하면 되는 부분이었는데 도메인이 아예 달라져서 이렇게 호출하려고 하면 크로스도메인 관련 오류가 떨어집니다.

이 문제를 해결하기 위해 몇 가지 트릭이 존재하는데 그 중에서 제가 찾은 가장 모던한 방법은 window.postMessage를 사용하는 겁니다.

일반적으로 서로 다른 페이지의 스크립트가 통신하기 위해선 프로토콜, 포트, 호스트(도메인)가 같아야만 가능한데 window.postMessage는 이런 제약들을 우회할 수 있다고 합니다. 그러면 보안이 문제가 될 수도 있는데 이게 다른 페이지의 메소드를 호출하는건 아니고 한쪽에선 메시지를 보내고 다른쪽에서 그 메시지를 처리하는 일종의 이벤트 이고 받는 쪽도 origin을 지정할 수 있기 때문에 보안에 큰 문제는 없어 보입니다. (단, jQuery postMessage 플러그인을 사용할 경우 window.postMessage를 지원하지 않는 브라우저에서는 origin이 무시됩니다.)

문제는 IE 8+ 부터 지원한다는 건데 다행히 jQuery postMessage 플러그인을 사용하면 IE6도 커버가 됩니다. 코드도 간단합니다. ajax 요청과 크게 다르지 않네요. window.postMessage를 지원하지 않는 경우엔 window.location에 해시(#)를 붙여 메시지를 보내고 window.location.hash 값을 모니터링하는 식으로 처리합니다. 기발하네요.

뷰 스크립트 간소화에 대한 이런저런 생각들

기본

최근에 두달 정도 진행한 프로젝트(댓글에 소셜을 추가)를 마감하고 든 생각 중 하나는 ‘자바스크립트 복잡도를 어떻게 줄일 수 있을까?’ 였습니다. 물론, jQuery를 사용하긴 하지만 뷰의 여러가지 인터랙션을 처리하다 보면 jQuery도 금새 복잡해지고 길어지더라구요. jQuery로 만들어진 스크립트가 복잡해 지고 있다는 기분이 드는 시점부터는 jQuery method chaining 도 무작정 좋아 보이지 만은 않았습니다. 쓰기엔 편하지만 이게 뭐하는 코드인지 이해하는 건 또 다른 문제 같구요. 그래서 ‘이 메소드 체이닝을 묶어서 적당한 이름의 함수로 빼볼까?’ 하는 생각도 많이 했었네요.

이런저런 고민 끝에 요새 JavaScript 쪽에서 많이 나타나고 있는 MV* 프레임워크에 눈이 가기 시작했습니다. 그런데 이게 종류가 원체 많다보니 혼란스럽기만 하더라구요. 그래서 봄싹 그룹스에 물어봤었고 많은 분들이 다양한 답변을 달아주셨습니다 🙂

답변을 정리해 보면..

1. AMD로 스크립트를 모듈화 시켜라

2. 프레임워크 적용이 배보다 배꼽이 더 클 수도 있다

3. Ember.js/KO/Backbone 추천

사실 저도 Ember.js에 흥미를 가지고 있었는데요.. 간단하다고 주장하는 Ember.js 홈페이지와는 다르게 예제를 봐도 복잡해 보여서(…) Require.js 부터 살펴봤습니다.

Require.js는 define() 으로 스크립트 덩어리를 모듈화 시켜놓고 require() 로 필요한 모듈만 호출해서 사용할 수 있습니다. 사용해 보니 괜찮았습니다만 ‘스크립트의 복잡성을 해결하는데 정말 큰 도움이 되는가?’ 는 잘 모르겠더라구요. 스크립트를 모듈화 시켜놓고 재사용 하는 측면에서 봤을 땐 당연히 좋겠지만 근본적인 스크립트 로직을 줄일 수 있는 방법은 아니라고 생각이 들었습니다.

그래서 Ember.js 를 살펴보기 시작했는데요. 이거 상당히 흥미로운 프레임워크 입니다. 먼저, Ember의 핵심은 자바스크립트를 OOP처럼 사용할 수 있도록 만들었다는 것에 있는 것 같습니다. 보통 서버쪽은 OOP인 경우가 많으니 거의 서버쪽 클래스와 매핑한다는 기분으로 스크립트 작성을 할 수 있더라구요. 그리고 jQuery 쓰면서 가장 많이 하는 작업 중 하나가 Ajax로 서버에서 데이터 가져와서 뷰에 보여주는 것인데요. jQuery로 이 작업을 하려면 데이터를 DOM에 매핑하는 부분이 손도 많이가고 복잡한데, Ember.js에 통합된 Handlebars.js라는 뷰 템플릿을 사용해 굉장히 쉽게 할 수 있습니다.

참 좋죠. 그런데 몇 가지 걸리는 부분이 있습니다.

첫 번째로 뷰 템플릿인데요. 사실 서비스 규모가 어느정도 되면 뷰 템플릿은 선택이 아닌 필수라고 생각합니다. 매번 페이지가 반복되는 부분 없이 다르진 않을 테니까요. Handlebars.js, Thymeleaf 등 요새 뷰 템플릿을 보면 내츄럴 템플릿을 강점으로 내세우는 것 같습니다. 그런데 jsp와 태그 라이브러리를 쓰다보면 이런 내츄럴 템플릿의 장점을 100% 활용하기 어려운 점이 있다는 거죠. 결국 내츄럴 템플릿을 최대한 활용하려면 서버 없이도 볼 수 있는 html로 뷰가 만들어져야 하는데 그러면 그동안 잘써온 태그 라이브러리는 어떻게 할것인지.. 그리고 Ember.js 를 사용하려고 보면 기존에 jQuery로 만들어둔 로직들을 Ember의 MVC안에 녹여 넣어야 합니다. 즉, 이건 이거대로 저건 저거대로가 아니라 Ember.js를 적용한다는 건 뷰 설계부터 Ember.js 에 맞게 만들어 져야 한다는 거죠. 왜냐면 라이브러리가 아니라 프레임워크 이니까요.

이런 맥락에서 jsp+jstl이 기존 방법이라면 내츄럴 템플릿 + js framework가 새로운 개발 트렌드라고 할 수 있지 않을까? 하는 생각을 해봅니다.

상황이 이렇다 보니 기존에 만들어진 서비스를 이런 형태로 녹여내는 건 정말 어려운 작업일 것 같습니다. 새로운 프로젝트에 사용하기 위해선 기존에 태그 라이브러리로 하던 작업을 다른 곳에서 처리할 수 있도록 해야할 테구요. 이 부분이 잘 커버된다면 서버단은 JSON만 던지게끔 설계하고 Ember.js(또는 비슷한 js framework)를 사용할 수 있는 환경에선 부산물이 거의 없는 시맨틱하고 퓨어(?)한 마크업에 MV* js 프레임워크 사용으로 획기적으로 스크립트를 줄일 수 있지 않을까.. 하고 생각해 봅니다.

최근 프로젝트 진행하며 사용한 유용한 jQuery 플러그인

기본

1. jQuery Placeholder

HTML5에 등장한 속성인 placeholder는 폼에 디폴트 문구를 표시할 수 있어 매우 유용합니다만.. IE에서 제대로 보여주지 못하는 치명적인 단점이 있습니다. 이를 보완할 수 있는 jQuery 플러그인! 사용법도 상당히 쉽습니다. placeholder 속성에 원하는 기본 문구를 작성한 후.. placeholder()를 뙇!

$("input").placeholder();
<input type="text" placeholder="Foobar"/>

2. jQuery Create Event

live() 함수가 deprecated 되긴 했지만.. 프로젝트에서 1.4.x 버전을 사용하기 때문에 별 고민 없이 사용한 플러그인 입니다. 이 플러그인은 live() 함수에서 “create” 이벤트(DOM에 새로 엘리먼트가 추가된 경우)를 감지할 수 있게 합니다.

$("someDiv").live("create", function(...));

Ajax로 서버에서 데이터를 받아온 후, 특정 부분이 업데이트 됐을 경우 어떤 행동을 해야한다면 이 플러그인을 써보세요.

3. jQuery Data Selector

jQuery API 중에 해당 DOM에 객체를 저장할 수 있는 data() 함수가 있습니다. 간단하게 key/value로 이루어져 있는데요. jQuery Data Selector 플러그인은 jQuery 셀렉터에 data()로 저장한 key/value를 검색할 수 있게끔 확장해 줍니다.

$(function(){
    // Attach data to the 2nd li
    $('#dataSelector li').eq(1).data('foo', 'bar');
    // Change the color of the li whose foo key is == bar
    $('#dataSelector li:data(foo=bar)').css('color', 'red');
});

4. jQuery Wordcount

트위터 글 입력 폼 같이 사용자가 몇 글자 입력했는지 알아보려고 textarea를 만든 다음에 keyup, keydown, keypress 같은 이벤트를 걸고 크로스브라우징 테스트를 해보면 특정 브라우저에서 생각대로 잘 동작하지 않습니다. 아쉬운 일이지만 브라우저에서 한글 키 입력 이벤트를 제대로 처리하지 못하기 때문인데요. 이를 보완하기 위해 타이머 이벤트로 특정 시간 마다 글자 수를 체크해서 업데이트 하는 플러그인을 만들어 봤습니다. 처음으로 만든 jQuery 플러그인이네요 ㅋ

사용법은 나름 간단합니다:

$("textarea").wordcount({
    countElement: $("span")
});
이번 프로젝트 진행하면서 만든 플러그인이 하나 더 있었네요! 두 번째 플러그인이군요. 이 플러그인은 jQuery UI Datepicker 예제에 나와있는 날짜 범위 선택을 재사용 하기 쉽게 만든 플러그인 입니다. 소소한 제한사항이 있으니 코드에 있는 주석을 꼭 읽어보세요.
사용법은 이런식입니다:
$("#from, #to").datepickerRange();
자매품으로 class 셀렉터를 사용할 수도 있습니다:
$(".from, .to").datepickerRange({
    dateFormat: "yy-mm-dd"
});
혹시 사용하다가 이상한 점을 발견하시면 이슈 등록 부탁드려요! (이 포스팅의 목적)

UTF-8에서 한글 바이트 크기

기본

회사에서 사용하는 오라클 DB에서 컬럼 제약이 VARCHAR2 300byte로 돼있었습니다. 저는 별 생각없이 한글 150자를 입력하고 테스트를 했는데 계속 실패. 이상하다 싶어서 글자 수를 줄이다가 결국 100글자에서 입력되는 걸 보고선 구글링을 하다가 UTF-8 바이트 크기라는 포스트를 발견했습니다.

아.. 한글은 3byte 구나. 팀 분이 말씀하시길 한글이 4byte인 경우도 있을거라고 하시더군요.

Textarea 한글 글자 수 카운팅 제대로하기

기본

추측컨데 한글이 조합형이라 발생하는 문제 같습니다.

어떤 문제냐면 textarea 글자 수 카운팅을 할 때, keydown, keyup, change 등등의 이벤트 핸들러를 바인딩 해놔도 한글을 입력하면 카운트가 제대로 업데이트 되질 않습니다. 몇몇 jQuery 플러그인이나 JavaScript 구현된 것을 구글링 해봤는데 코드는 대동소이하더라구요. 문제도 여전히 발생하고. 사실 영어는 문제 발생하지 않으니 아마 고려하지 않았을겁니다.

이 문제를 해결한 곳이 두 군데 있는데 하나는 미투데이고 다른 하나는 트위터입니다. 미투 같은 경우엔 focus가 발생했을 때, setInterval() 함수를 이용해 업데이트를 시작하고 다시 blur()가 되면 setInterval()을 해지시키는 식으로 구현했습니다. 물론, 좀 비효율적이긴 하지만 이렇게 안하면 어떻게 구현하나 싶기도 하네요.

트위터는 어떤식으로 구현하는지 아직 살펴보지 못했는데 한 번 확인해 봐야겠네요.

js 구현체 Github 링크

jQuery의 event.stopPropagation()

기본

회사 코딩하던 중에 다음과 같은 문제에 봉착했습니다:

제공받은 마크업 셀렉트 박스가 있는데 마치 콤보박스같이 클릭하면 아래로 몇 개의 리스트가 나타납니다. 따라서 제목을 클릭했을 때 리스트가 나타나고 사라져야하며, 또한 셀렉트 박스 외의 다른 지점을 클릭했을 경우 리스트가 사라져야 합니다.

처음엔 focusout()을 사용해보려고 했는데 제목을 누른 후 나타난 리스트를 클릭할 경우 focusout  이벤트가 발생해 리스트를 클릭할 수가 없습니다. 그래서 body에 click() 이벤트를 걸어서 해당 리스트를 hide() 하려고 했더니 모든 클릭 이벤트를 먹어서 제목을 클릭했을 때 리스트가 나타나질 않습니다.

팀원 분에게 물어보니.. 팀장님이 그럴 때 stopPropagation()을 사용하라고 하시더라구요. 사실 그동안 많이 봤던 함수인데 무슨 기능 하는지 모르고 있었습니다. 무슨 기능인고 하니, 이벤트가 발생하면 버블링(트리를 타고 올라가서)해서 루트까지 올라가게 되는데 이를 막아주는 기능이라고 합니다. 즉, 셀렉트 박스의 제목에 걸어두면 body의 click() 이벤트 핸들러로 가는걸 막아주며, 따라서 원래 제목에 걸어둔 이벤트 핸들러가 동작하게 됩니다.

그래서 다음과 같이 stopPropagation()을 먼저 해줘야 합니다.

$(“#listBoxTitle”).click(function(e) {

e.stopPropagation();

// 하고 싶은 것

});

같은 맥락의 delegate() 라는 함수가 있는데, 이 함수로 특정 엘리먼트에 이벤트 핸들러를 등록해두면 DOM 트리 상 하위에 있는 엘리먼트가 버블링 시키는 이벤트를 document까지 안올리고 여기서 처리하게 됩니다.

그나저나 jQuery 1.7 에선 live, delegate 함수 모두 on() 으로 통합되었다는 군요.