들어가며

패럴랙스 스크롤링 웹 사이트의 세계로 들어갈 준비는 되었나요? 패럴랙스 스크롤을 사용한 사이트는 많습니다. 안타깝게도 일부 사이트에 있는 패럴랙스 스크롤링은 사용자들의 주의를 분산시키거나 보여주고자 했던 콘텐츠가 아닌 다른 곳으로 사용자들의 눈을 돌리지만, 제대로만 사용한다면 훨씬 더 빼어난 웹을 만들 수 있습니다. 패럴랙스는 잘만 사용된다면 사용자들이 더 실감 나는 매력적인 방식으로 콘텐츠를 탐색할 수 있도록 도와줍니다.

최근 우리팀은 콘텐츠 일부에 패럴랙스 스크롤 애니메이션을 사용하기 시작했습니다. 우리는 ADT의 역사라는 페이지에서 약간의 아이디어를 얻고, 유명 드라마인 워킹 데드에 대한 인터랙티브 좀비 인포그래픽을 만들어보기로 했습니다. 오늘은 이 프로젝트의 무대 뒤로 여러분을 데려가 굉장히 유용했던 Skrollr.js라는 자바스크립트 플러그인의 사용법을 보여주려고 합니다.

메인 좀비 이미지

간단히 말해서 Skrollr는 HTML과 CSS를 사용해 정교한 스크롤 기반 애니메이션(패럴랙스 혹은 그 밖의 것)을 만드는 플러그인입니다. Skrollr의 수많은 장점은 공식 문서에서 찾아볼 수 있습니다. 이 글에서 우리는 자바스크립트와 스프라이트 몇 개를 사용해 사용자가 스크롤을 앞뒤로 움직임에 따라 반응하는 보행 애니메이션을 간단하게 만들어보겠습니다. 이 글을 끝까지 따라가면, 패럴랙스 환경에서 걷는 캐릭터가 인간에서 좀비로 변하는 것도 볼 수 있습니다.

먼저 몇 가지 소스 파일을 다운로드 받으세요. 워킹 데드 프로젝트에서 사용했던 이미지 몇 장과 자바스크립트 파일, HTML 뼈대가 있을 것입니다. 이제 이 파일들을 가지고 삽질을 시작해보겠습니다.

1단계 - 패럴랙스 백그라운드

HTML5 data- 속성을 추가한 <div> 몇 개를 추가해서 패럴랙스 백그라운드 레이어 두 장을 만들어 보겠습니다. 또한, 스타일시트에 CSS도 약간 추가하고 우리가 작성한 main.js 파일에서 Skrollr의 .init() 함수도 호출할 것입니다. 다음 코드에서 보듯 패럴랙스 레이어는 id="skrollr-body"가 설정된 엘리먼트의 자식 노드여야 합니다. 지금 보기에는 클래스와 ID가 너무 많다 싶을 수 있지만, 나중에 엘리먼트를 조금 더 추가하게 되면 이유가 있었음을 알게 될 것입니다.

HTML:

<div id="skrollr-body">
	<div id="Scene">
		<div id="bg1" class="parallax-layer"
			data-0="left:0px;"
			data-5000="left:-1000px;">
		</div>
		<div id="bg2" class="parallax-layer"
			data-0="left:0px;"
			data-5000="left:-2500px;">
		</div>
	</div>
</div>

우리가 보게될 마술같은 일은 모두 data- 속성 덕분입니다. Skrollr를 호출하면, Skrollr는 #skrollr-body 안에 있는 모든 엘리먼트를 탐색하며 엘리먼트에 설정된 data- 속성을 사용해 적절한 애니메이션을 구현합니다. data- 뒤에 붙은 숫자는 사용자가 스크롤 한 픽셀의 수이며, 속성의 값은 해당 스크롤 위치에 왔을 때 현재의 요소에 설정할 스타일입니다. #bg1를 예로 들면, 사용자가 페이지 상단(data-0)으로부터 페이지 아래로 5,000 픽셀(data-5000)만큼 스크롤하면 #bg1이 왼쪽으로 1000 픽셀만큼 움직이는 애니메이션이 나타날 것입니다. 설정한 값을 보면 Skollr는 대략 사용자 스크롤 5픽셀마다 왼쪽으로 1픽셀씩 #bg1을 옮길 것입니다. 이 애니메이션은 앞으로도 뒤로도 일어나므로 사용자는 어느쪽으로든 스크롤 할 수 있으며 Skrollr이 적절한 애니메이션을 보여줄 것입니다.

#bg2data-* 속성에 설정된 값을 살펴보면 사용자 스크롤 2픽셀마다 #bg2가 1픽셀씩, 다시 말해 #bg1보다 훨씬 빨리 움직이는 것을 알 수 있습니다. 이 덕분에 3D 공간 같은 느낌이 날 것입니다. 그러나 이 코드를 실행하기 전에 이미지를 추가한 후 액자처럼 감싸는 CSS를 추가해야 합니다. 그 후에는 Skrollr의 초기화 함수도 호출해야 하고요.

CSS:

화면은 700px 높이의 프레임에 수직 중간 정렬되게 합니다.

#Scene{
	position: fixed;
	width: 100%;
	height: 700px;
	margin-top: -350px;
	top: 50%;
	}
.parallax-layer{
	position: absolute;
	height: 700px;
	background-repeat: no-repeat;
	}
#bg1{
	background: url(../images/bg-1.jpg);
	width: 3528px;
	}
#bg2{
	background: url(../images/bg-2.png) left bottom;
	/* 이미지가 꽤 크지만... 사용할만한 가치가 있습니다 */
	width: 4368px;
	}


JavaScript:

skrollr.init();

잠시 후에는 여기에 다른 작업을 더 추가할 것이므로 여기까지 작업한 내용을 별도 파일로 저장했습니다. 하지만, 여러분은 굳이 그렇게 하지 않아도 됩니다.

이것 보세요! 패럴랙스가 만들어졌네요!

2단계 - 전경 엘리먼트

다음으로는 전경에 몇 가지 요소를 추가해보겠습니다. 구름, 해, 학교를 추가한 후 캐릭터도 추가할 것입니다. 이 중 학교는 캐릭터가 인간에서 좀비로 변신할 때 잠시 캐릭터를 숨기는 용도로 사용합니다.

먼저 두 번째 구름 레이어를 추가해봅시다. 이 구름 레이어는 #bg2와 같은 속도로 화면을 가로질러 이동할 것이므로, #bg2 안에 구름 레이어를 추가하여 (절대 위치에 기반한) 동일한 애니메이션이 적용되도록 합니다. 이처럼 내부에 있는 div는 부모의 CSS 위치 속성을 그대로 사용하는 경우가 많습니다.

HTML:

<div id="bg2" class="parallax-layer"
	data-0="left:0px;"
	data-5000="left:-2500px;">
	<div id="cloud"></div>
</div>

CSS:

#cloud{
	position:absolute;
	background:url(../images/clouds.png);
	width:2059px;
	height:347px;
	}

이제 학교와 아직 좀비가 되기 전인 캐릭터를 추가해보겠습니다. 학교는 #bg2보다 살짝 더 빠르게 움직이게 할 것입니다. 또한, 학교를 그릴 때 뒤쪽과 앞쪽 레이어를 나누고 그 사이에 좀비 캐릭터를 두어서 마치 캐릭터가 문을 통과해서 지나가는 것처럼 보이게 할 것입니다.

HTML:

<div class="parallax-layer">
	<div id="schoolunder" class="school"
		data-0="left:2000px;"
		data-5000="left:-1500px;">
	</div>
	<div id="zombie"></div>
	<div id="schoolover" class="school"
		data-0="left:2000px;"
		data-5000="left:-1500px;">
	</div>
</div>

CSS:

캐릭터는 화면 왼쪽에서 300px만큼 떨어진 곳에 그대로 있되 배경이 화면 좌우로 움직이도록 하여 마치 예전에 보던 횡 스크롤 게임 느낌이 나도록 했습니다.

#zombie{
	position:absolute;
	background-image:url(../images/zombify.png);
	width:250px;
	height:190px;
	top:340px;
	left:300px;
	}
.school{
	position:absolute;
	width:600px;
	height:523px;
	top:100px;
	}
#schoolunder{
	background:url(../images/school_under.png);
	}
#schoolover{
	background:url(../images/school_over.png);
	}

이제 이 캐릭터는 마치 스케이트를 타듯 미끄러지며 화면을 이동하는 것처럼 보일 텐데, 여기에 보행 애니메이션과 짤막한 좀비 변신 애니메이션을 추가해보겠습니다. 그전에 해 이미지부터 추가하고 넘어가죠. 우리는 5개의 data 속성을 사용하여 해가 뜨고 지는 애니메이션을 표현했습니다. 이 엘리먼트는 #bg1#bg2 사이에 둘 것이므로 하늘 배경보다는 앞에 보이지만 전경 엘리먼트 뒤쪽을 이동하게 될 것입니다.

HTML:

<div id="bg1" class="parallax-layer"
	data-0="left:0px;"
	data-5000="left:-1000px;">
</div>
<div id="sun"
	data-0="top:200px;"
	data-2000="top:25px;"
	data-3000="top:0px;"
	data-4000="top:25px;"
	data-5000="top:50px;">
</div>
<div id="bg2" class="parallax-layer"
	data-0="left:0px;"
	data-5000="left:-2500px;">
</div>

CSS:

#sun {
	position:absolute;
	background:url(../images/sun.png);
	width:194px;
	height:194px;
	left:180px;
	}

우리가 지금까지 한 내용을 확인해보세요. 꽤 괜찮지만, 아직 다듬어야 할 부분이 남아 있습니다.

3단계 - 계속 걷게 하기 (& 좀비로 변신하기)

이제 캐릭터에 생명력을 불어넣을 때입니다. 캐릭터의 보행 및 변신 애니메이션에 필요한 이미지 프레임은 다운로드 받은 .png 스프라이트 파일 안에 있습니다. 처음에는 인간이었다가 나중에 좀비로 변할 것입니다. 이 프레임들을 배경 이미지로 보여주고 사용자의 스크롤에 따라 주기적으로 반복시키는 자바스크립트를 작성해보겠습니다. 스크롤을 어느 쪽으로 하든 동작하게 만들어서 정말 게임 같은 느낌을 내보겠습니다.


좀비화를 표현하는 스프라이트

data-* 속성을 사용하여 Skrollr가 배경 이미지를 애니메이션으로 만들게 할 수도 있지만, 이 방법은 속성을 꽤 많이 작성해야 하므로 직접 함수를 작성하기로 합니다. 직접 작성한 덕분에 약간의 유연함도 얻을 수 있으며 코드의 유지보수도 확실히 더 편해졌습니다. 우리는 skrollr.init()를 호출할 때 우리가 작성한 함수를 인수로 전달할 것입니다. 조금 더 자세히 말하자면 beforerender 리스너 함수로 할당하여 Skrollr가 애니메이션의 각 프레임을 그리기 직전에 자동으로 호출되게 할 것입니다(beforerender를 비롯한 Skrollr의 다른 옵션은 문서를 참고하세요). beforerender에는 curTop이라는 프로퍼티를 가진 객체가 인수로 전달됩니다. curTop은 현재 스크롤이 상단으로부터 얼마나 떨어졌는가를 알려주는, 다시 말해 페이지 상단으로부터 사용자가 스크롤 한 픽셀의 양을 알려주는 숫자입니다. 우리는 이 값을 사용하여 배경 이미지로 사용한 스프라이트를 앞으로 움직일 것인지 뒤로 움직일 것인지 또는 인간을 좀비로 바꿔야 할 때인지 정하겠습니다.

보행 애니메이션부터 작업한 후 인간에서 좀비로 변신하는 과정을 추가하겠습니다.

JavaScript:

var zombie = $('#zombie'),
	pLocs = [0, -250, -500, -750, -1000, -1250, -1500]
	curFrm = 0,
	lastStep=0;

skrollr.init({
	beforerender: function(o){
		// 마지막에 백그라운드 이미지를 움직인 후에
		// 사용자가 50픽셀 아래로 스크롤하면
		// 앞으로 이동해야 하므로 스프라이트에 있는
		// 다음 프레임으로 옮긴다.
		if(o.curTop > lastStep + 50) {
			if (curFrm>=6){ curFrm=-1; }
			zombie.css('background-position', pLocs[curFrm++] + 'px 0px');
			lastStep = o.curTop;
		// 사용자가 50픽셀 위로 스크롤하면
		// 뒤로 이동해야 하므로 이전 프레임으로 옮긴다.
		} else if(o.curTop < lastStep - 50) {
			if (curFrm<=0){ curFrm=7; }
			zombie.css('background-position', pLocs[curFrm--] + 'px 0px');
			lastStep = o.curTop;
		}
	}
});
  • zombie — 캐릭터를 표현하는 div에 대한 참조
  • pLocs — 스프라이트의 각 프레임이 왼쪽 끝으로부터 떨어진 픽셀 위치를 담은 배열
  • curFrm — pLoc에 있는 보행 애니메이션 프레임 중 현재 사용 중인 프레임의 인덱스
  • lastStep — 가장 최근에 배경 이미지를 움직였던 스크롤 위치. 프레임을 앞/뒤 어느 쪽으로 이동할 것인지 계산할 때 사용

멋지네요! 어려운 부분이 끝났습니다. 우리의 좀비는 걷기 시작할 테고요. 이제 남은 단계는 좀비로 변신!밖에 없습니다.

어쩌면 워킹 데드 드라마와 약간 다를지도 모르는데, 이 프로젝트에서는 캐릭터의 좀비 변신이 학교(zombie school)로 표현되었습니다. 덕분에 이 과정은 상대적으로 편했습니다. 인간이 걷는 장면의 프레임과 좀비가 걷는 장면의 프레임은 같은 이미지에 있었고 인간이 걷는 장면 바로 뒤에 좀비가 걷는 장면이 있었으므로 사용자가 캐릭터가 학교를 지나가는 장면이 나오는 곳을 스크롤 할 때 #zombie 레이어 배경 이미지의 위치만 적당히 바꿔주면 됐습니다. 인간이 걷는 장면은 7프레임인데 반해 좀비가 걷는 장면은 4프레임 밖에 안 들어서 애니메이션이 조금 더 유연하게 동작하도록 코드를 살짝 손봐야 했습니다. 수정된 부분은 아래에 굵은 글씨로 표시해두었습니다.

JavaScript:

var zombie = $('#zombie'),
	pLocs = [0, -250, -500, -750, -1000, -1250, -1500],
	curFrm = 0,
	lastStep=0,
	// We need just a couple extra variables
	animationCycle, backPosY;

skrollr.init({
	beforerender: function(o){
		// 사용자가 2800픽셀 이하로 스크롤하면
		// 캐릭터를 그대로 인간인 상태로 두고
		// 그 이상 스크롤하면 좀비로 바꾼다.
		if(o.curTop < 2800) {
			animationCycle=7;
			backPosY= '0px';
		} else {
			animationCycle=4;
			backPosY= '-190px';
		}
		if(o.curTop > lastStep + 50) {
			if (curFrm>=animationCycle-1){ curFrm=-1; }
			zombie.css('background-position', pLocs[++curFrm] + 'px ' + backPosY);
			lastStep=o.curTop;
		} else if(o.curTop < lastStep - 50) {
			if (curFrm<=0){ curFrm=animationCycle; }
			zombie.css('background-position', pLocs[--curFrm] + 'px ' + backPosY);
			lastStep = o.curTop;
		}
	}
});

그럼 이제 끝났습니다. 지금 막 우리는 게임 스타일의 패럴럭스 스크롤링을 만들었습니다. 축하합니다! 만약 더 다듬어진 버전을 보고 싶다면 우리팀이 작성한 워킹 데드 데모를 확인해보세요.

마무리

여기서 한 것은 Skrollr로 할 수 있는 기능의 겉핥기에 지나지 않습니다. 따라서 가능하다면 다른 많은 기능에 대해서도 꼭 읽어볼 것을 추천합니다. 애니메이션에 이징(easing)을 적용하거나 data 속성과 상수를 조합해서 사용하거나(유지보수에 좋습니다) Skrollr 스타일 시트에 프레임을 추가하는 대신 마크업에 전체 키프레임을 넣는 등 흥미로운 기능이 많습니다.

끝으로 잠깐 몇 마디 덧붙이려고 합니다. 가끔 웹 디자이너인 우리들은 매체의 노예처럼 느껴질 때가 있습니다. 웹에는 제약이 많고 크로스 브라우저와 크로스 디바이스 이슈에서 오는 어려움도 많습니다. 최소한 저는 여러 매체에서 디자인과 개발을 하는 한 사람으로서 간혹 매체의 노예처럼 느껴질 때가 있습니다. 하지만 이러한 브라우저 기반 매체에는 매우 독특한 면이 있는 것도 사실입니다. 예를 들어, 스크롤링 덕분에 사용자와 이런 식으로 인터랙션 할 수 있는 기회가 생겼습니다. 개인적으로 디자이너들은 이런 고유한 특성을 알아두어야 하며, 항상 이러한 특성을 훌륭한 경험으로 창조해 낼 방법을 찾아야 한다고 생각합니다.


이 글은 Elli Bishop이 오페라 개발자 사이트에 게시한 Creating Game-Style Parallax Scrolling: Zombie Edition을 번역한 글입니다.

Posted by 행복한고니 트랙백 0 : 댓글 1

NoSQL은 상당히 오랫동안 뜨거운 화제였다(음, 이제는 단순한 화젯거리 수준이 아니다).
하지만, 진짜로 NoSQL을 사용해야 할 때는 언제일까?

MongoDB의 적절한 사용법

NoSQL 제품(그리고 MongoDB)은 특정한 문제를 해결하기 위해 사용되어야 한다. 만약 다음과 같은 문제를 겪고 있다면 MongoDB를 고려해보는 것이 좋다.

쓰기 부하가 클 것이 예상될 때

MongoDB는 기본적으로 안전한 트랜잭션을 통해 빠른 속도로 데이터를 삽입한다. 개별 데이터의 비즈니스 가치가 낮은 어마어마한 양의 데이터를 읽어들여야 한다면 MongoDB가 적합하다. 단, 100만건이 넘는 트랜잭션 레코드는 삽입하지 않아야 하며, 최소한 다른 안전 장치를 갖춘 후에 삽입하는 것이 좋다.

신뢰할 수 없는 환경(클라우드와 실생활)에서 고가용성(高可用性)이 필요할 때

MongoDB에서는 replicaSet(마스터-슬레이브로 동작하는 서버의 집합)을 쉽고 빠르게 설정할 수 있다. 게다가, 노드(혹은 데이터 센터)에 문제가 생겼을 때 자동으로 데이터를 안전하게 즉시 복구할 수 있다.

빅 데이터를 다루거나 샤딩이 필요할 때

데이터베이스 스케일링은 어렵다(MySQL 테이블은 테이블당 5~10GB 사이가 되면 성능이 저하된다). MongoDB에는 데이터베이스의 파티셔닝 또는 샤딩이 필요할 때 사용할 수 있는 솔루션이 내장되어 있다.

위치 기반 데이터일 때

MongoDB는 특수한 기능을 내장하고 있어서 특정 위치와 관련한 데이터를 빠르고 정확하게 찾을 수 있다.

데이터가 커지거나 (1GB 이상) 스키마가 고정되어 있지 않을 때

RDBMS에 새로운 칼럼을 추가하면 일부 데이터베이스에서는 전체 데이터베이스에 락을 걸고, 그 외의 데이터베이스에서는 심각한 부하와 성능 저하를 일으킨다. 일반적으로 이런 현상은 테이블의 크기가 1GB보다 클 때 발생한다(또한, 아래에서 설명하는 BillRun과 갈이 크기가 수 TB를 넘는 테이블이 여러 개 존재하는 시스템에는 심각한 문제가 되기도 한다). MongoDB는 스키마가 없는 시스템이므로 새 필드를 추가해도 기존에 저장된 로우(혹은 도큐먼트)는 전혀 영향을 받지 않으며 변경이 즉시 이루어진다. 다른 장점으로는 프로그램이 변경되서 스키마를 수정할 때 DBA가 없어도 된다는 것이다.

DBA가 없을 때

DBA도 없고 데이터를 정규화하거나 조인(join)하기도 싫다면 MongoDB를 고려하는 것이 좋다. MongoDB는 객체를 JSON으로 직렬화하여 그대로 MongoDB에 저장하므로 객체를 저장하기에 좋다. 주의: 빅 데이터를 다룰 것이라면 위험 요소를 피하기 위해 다음과 같은 방법을 따라야 한다.

BillRun - Billing on top of MongoDB | MUG IL, Feb 2014 from Ofer Cohen

실제 사례 연구: 결제 시스템

지난 일리노이 모델링 사용자 그룹(Illinois Modeling Users Group, ILMUG)에서 오퍼 코헨은 MongoDB를 데이터 저장소로 사용한 차세대 오픈소스 결제 솔루션인 BillRun에 대해 발표했다. BillRun 시스템은 매월 5억건 이상의 통화 기록을 처리하는 이스라엘에서 가장 빠르게 성장하는 통신망 기업에서 사용되었다. 이 발표에서 오퍼는 이 시스템이 MongoDB를 사용해서 얻은 장점에 대해 설명했다.

  1. 스키마가 없는 설계 덕분에 새로운 통화 기록 유형을 시스템에 빠르게 도입할 수 있었다. 덕분에 BillRun은 데이터 저장소의 보편성을 유지할 수 있었다.
  2. 새 필드 추가를 제한하거나 데이터 증가를 제한하지 않고도 BillRun은 이미 실무에서 테이블당 수 TB에 달하는 데이터를 다루었다.
  3. 빠른 replicaSet으로 인해 다중 데이터 센터의 DRP(재난 복구 프로토콜)과 HA(고가용성) 솔루션 구성할 때 필요한 규약을 쉽게 충족시킬 수 있다.
  4. 샤딩을 통해 예산을 다 쓰지 않고도 선형적, 수적인 증가가 가능했다.
  5. 초당 2천건 이상의 통화 기록을 삽입할 때처럼 MongoDB 아키텍쳐는 삽입 부하가 높은 시스템에 적합하다. findAndModify(속도가 느림)와 2단계 실행(프로그램 적인 방법)을 통해 트랜잭션을 안전하게 만들 수 있다.
  6. 개발자 지향적인 쿼리덕분에 개발자들은 품격있는 쿼리를 작성할 수 있다.
  7. 위치 기반 기능을 활용해 사용자의 사용 패턴을 분석하고 어디에 통신망 인프라를 투자할 것인지 정했다.

요점

MongoDB는 훌륭한 도구지만 이득을 얻으려면 적합한 시나리오에서 사용해야 한다. BillRun은 MongoDB를 사용하기에 좋은 사례였다.



이 글은 Moshe Kaplan이 작성한 When Should I Use MongoDB rather than MySQL (or other RDBMS): The Billing Example을 번역한 글입니다.

Posted by 행복한고니 트랙백 0 : 댓글 0

웹앱에는 대용량 데이터나 바이너리 파일을 오프라인으로 저장할 수 있는 기능이 있습니다. 심지어 MP3 파일을 캐시하는 것도 가능합니다. 이미 웹 브라우저 기술은 오프라인으로 데이터를 저장할 수 있으며, 대용량도 저장할 수 있습니다. 문제는 사용할 방법이 파편화되어 있다는 것입니다.

localStorage는 매우 단순한 데이터 저장소이지만, 속도도 느리고 대용량 바이너리 데이터를 다룰 수 없습니다. IndexedDB와 WebSQL은 비동기 식이며 빠르고 대용량도 다룰 수 있지만 API가 직관적이지 못합니다. 심지어 아직도 주요 브라우저 중에는 IndexedDBWebSQL를 둘 다 지원하지 않는 것도 있으며 가까운 시일 내에는 이런 상황이 나아질 것 같지도 않습니다.

만약 오프라인을 지원하는 웹앱을 작성해야 하고, 어디서부터 시작해야 할지 갈피를 못 잡겠다면 이 글이 유용할 것입니다. 오프라인 지원 기능은 한 번도 다뤄본 적이 없지만, 이 기능 때문에 골치 아픈 분이 읽어도 좋습니다. 모질라에서 만든 localForage는 어떤 브라우저에서도 손쉽게 데이터를 오프라인으로 저장할 수 있게 해 주는 라이브러리입니다.

저는 around라는 HTML5 포스퀘어 클라이언트를 개발하며 오프라인 저장소의 문제점들을 경험했습니다. localForage 사용법은 이 글에서 설명하겠지만, 코드를 꼼꼼히 보고 배우는 것을 좋아하는 분들에게는 소스도 공개되어 있습니다.

localForage는 매우 단순한 localStorage API를 사용하는 자바스크립트 라이브러리로서, get, set, remove, clear, length와 같은 기본적인 기능은 물론 다음과 같은 기능도 지원합니다.

  • 콜백을 사용한 비동기 API
  • IndexedDB, WebSQL, localStorage 드라이버 (가장 적절한 드라이버를 자동으로 선택)
  • Blob와 임의의 데이터 타입을 지원하여 이미지, 파일 등 저장 가능
  • ES6 Promises 지원

IndexedDBWebSQL을 포함한 덕분에 localStorage만 사용할 때보다 더 많은 데이터를 저장할 수 있으며, 이들의 비동기적 특성 덕분에 get/set 함수를 호출해도 메인 쓰레드가 느려지지 않으므로 앱이 더 빨라질 수 있습니다. promises를 지원하므로 콜백 수프(callback soup, 콜백이 너무 많아서 프로그램의 흐름을 알기 어렵게 된 상태) 없이 자바스크립트를 작성할 수 있습니다. 물론 콜백을 좋아한다면 localForage는 그 방법도 지원합니다.

얘기는 그만. 어떻게 동작하는지 보여줘!

localStorage API는 여러 경우에 있어 사실 꽤 훌륭합니다. 사용하기 편하고 복잡한 데이터 구조를 만들지 않아도 되고, 단순하여 별도의 코드 조각이나 라이브러리가 따로 필요하지 않습니다. 예를 들어, localStorage를 사용해 앱 설정을 저장하고 싶다면 다음과 같이 작성할 수 있습니다.

// 오프라인으로 저장할 설정값
var config = {
    fullName: document.getElementById('name').getAttribute('value'),
    userId: document.getElementById('id').getAttribute('value')
};
 
// 다음에 앱을 실행할 때 사용하기 위해 설정값을 저장한다.
localStorage.setItem('config', JSON.stringify(config));
 
// 다음에 앱을 실행할 때 다음과 같이 사용할 수 있다.
var config = JSON.parse(localStorage.getItem('config'));

단, localStorage에는 문자열 형식으로 값을 저장해야 하므로 값을 JSON 형태로 혹은 JSON 형태에서 변환해야 합니다.

아주 기분 좋을 정도로 직관적이지만 금세 localStorage에 있는 문제점을 깨닫게 될 것입니다.

  1. 동기식이다. 데이터가 얼마나 크던 데이터를 디스크에서 읽어 들여 해석할 때까지 기다려야 합니다. 이 때문에 앱의 반응성이 느려질 것입니다. 이는 특히 모바일 디바이스에 안 좋은데 데이터를 완전히 읽어 들일 때까지 메인 쓰레드가 대기해야 하므로 여러분의 앱은 느리고 반응성까지 떨어지는 것처럼 보일 것입니다.
  2. 문자열만 지원한다. 반드시 JSON.parseJSON.stringify를 사용해야 합니다. 이는 localStorage가 값으로 자바스크립트 문자열 형식만 지원하기 때문입니다. 숫자도, 불리언도, 대용량 바이너리 데이터 등도 저장할 수 없습니다. 이 때문에 숫자나 배열을 저장하는 작업은 귀찮아지고, 대용량 바이너리 데이터를 저장하는 것은 사실상 불가능합니다(최소한 엄.청. 짜증나고 느릴 것입니다).

localForage를 사용한 더 좋은 방법

localForage는 localStorage의 API를 사용하면서도 비동기식 API를 사용해 이 같은 문제를 극복했습니다. 다음은 같은 데이터를 저장할 때 IndexedDB와 localStorage의 사용법을 비교한 것입니다.

IndexedDB 코드

// IndexedDB.
var db;
var dbName = "dataspace";
 
var users = [ {id: 1, fullName: 'Matt'}, {id: 2, fullName: 'Bob'} ];

var request = indexedDB.open(dbName, 2);
 
request.onerror = function(event) {
    // 에러 처리
};
request.onupgradeneeded = function(event) {
    db = event.target.result;
 
    var objectStore = db.createObjectStore("users", { keyPath: "id" });
 
    objectStore.createIndex("fullName", "fullName", { unique: false });
 
    objectStore.transaction.oncomplete = function(event) {
        var userObjectStore = db.transaction("users", "readwrite").objectStore("users");
    }
};
 
// 데이터베이스가  생성되고 나면 사용자를 추가한다
 
var transaction = db.transaction(["users"], "readwrite");
 
// 데이터가 데이터베이스에 모두 저장되었을 때 할 일
transaction.oncomplete = function(event) {
    console.log("All done!");
};
 
transaction.onerror = function(event) {
    // 에러도 빠뜨리지 말고 다루어야 한다
};
 
var objectStore = transaction.objectStore("users");
 
for (var i in users) {
    var request = objectStore.add(users[i]);
    request.onsuccess = function(event) {
        // Contains our user info.
        console.log(event.target.result);
    };
}

WebSQL은 번잡하다 싶을 정도는 아니지만 그래도 기본 코드가 약간 필요하긴 합니다. localForage에서는 다음과 같이 사용하면 됩니다.

localForage Code

// 사용자를 저장한다
var users = [ {id: 1, fullName: 'Matt'}, {id: 2, fullName: 'Bob'} ];
localForage.setItem('users', users, function(result) {
    console.log(result);
});

얼마 차이 안나는군요?

문자열 외의 데이터 저장하기

사용자의 프로필 이미지를 다운받은 뒤 오프라인 상태에서 볼 수 있도록 캐시한다고 생각해 봅시다. localForage에서는 바이너리 데이터를 간단하게 저장할 수 있습니다.

// AJAX를 사용해서 사용자의 사진을 다운로드한다
var request = new XMLHttpRequest();
 
// 첫 번째 사용자의 사진 가져오기
request.open('GET', "/users/1/profile_picture.jpg", true);
request.responseType = 'arraybuffer';
 
// AJAX 상태가 변경되면 사진을 로컬에 저장한다.
request.addEventListener('readystatechange', function() {
    if (request.readyState === 4) { // readyState DONE
        //localStorage로는 바이너리 데이터를 있는 그대로 저장할 수 없었을 것이다.
        localForage.setItem('user_1_photo', request.response, function() {
            // 사진이 저장되었다. 다음 단계를 진행하자.
        });
    }
});
 
request.send();

저장한 사진을 가져올 때는 코드 3줄만 있으면 된다.

localForage.getItem('user_1_photo', function(photo) {
    // data URI 등을  만들어 img 태그 등에 사진을 표현한다
    console.log(photo);
});

Callback과 Promise

코드에서 콜백을 사용하고 싶지 않다면, localForage에서 콜백 함수를 인수로 사용하는 대신 ES6 Promise를 사용할 수 있습니다.

localForage.getItem('user_1_photo').then(function(photo) {
    // data URI 등을  만들어 img 태그 등에 사진을 표현한다
    console.log(photo);
});

사실 이 예제는 조금 억지로 만든 감이 있습니다. 그러나 around를 살펴보면 이 라이브러리가 실제로 사용되는 것을 볼 수 있습니다.

크로스 브라우저 지원

localForage는 최근 브라우저를 모두 지원합니다. IndexedDB사파리 외의 모든 최근 브라우저에서 지원하고 (IE 10+, IE Mobile 10+, Firefox 10+, Firefox for Android 25+, Chrome 23+, Chrome for Android 32+, and Opera 15+), 내장 안드로이드 브라우저(2.1+)와 사파리는 WebSQL을 사용합니다.

가장 안 좋은 경우라 해도 localForage는 localStorage를 대비책으로 사용하므로 최소한 기본적인 데이터는 오프라인으로 저장할 수 있게 됩니다(하지만 이 경우 Blob은 저장할 수 없고 많이 느릴 수도 있다). 그러나 적어도 자동으로 데이터를 JSON 문자열로 변환 혹은 JSON 문자열을 데이터로 변환해주는 정도의 이점은 얻을 수 있습니다.

localForage에 대한 자세한 정보는 Github에서 볼 수 있으며 localForage가 해줬으면 하는 기능이 있다면 이슈에 추가해주세요.

이 글은 localForage: Offline Stroage, Improved를 번역한 글입니다. 원문의 라이센스에 따라 CC BY-SA로 공개합니다.


Posted by 행복한고니 트랙백 0 : 댓글 0

이 글은 W3C의 Mobile Web Best Practices 1.0을 번역 및 요약 정리한 글입니다. 최대한 원문의 의미를 그대로 전달하려고 노력했지만 번역 및 요약 과정에서 잘못 전달되거나 누락된 부분이 있을 수도 있으니, 이 점을 감안하고 봐주시기 바랍니다. 편의상 글 내용에서는 높임말을 사용하지 않았으니 양해부탁드립니다.


모바일 핸드폰CC licensed image by Irita Kirsbluma


모바일 웹 모범 사례는 모바일 기기에서 사용하는 웹의 사용자 경험을 증진시킬 목적으로 만들어졌다. 따라서 콘텐츠 자체에 대해서는 다루고 있지만, 콘텐츠를 만드는 방법, 사용하는 모바일 기기나 브라우저에 대해서는 다루지 않는다.

1. [의미적 일관성] 하나의 URI에서 제공하는 콘텐츠는 서로 다른 기기에서 접근하더라도 하나의 의미적으로 일관성있는 경험을 제공하라.

어떤 기기에서 접근해도 동일한 사용자 경험을 제공해야 한다.

2. [기능] 디바이스의 기능을 최대한 잘 활용하여 개선된 사용자 경험을 제공하라.

3. [결함] 합리적인 단계를 통해 지원되지 않는 기능을 우회하라.

데스크톱과 마찬가지로 모바일 브라우저에도 차이가 있고 브라우저 별로 지원하는 기능에 차이가 있을 수 있다. 관련 표준의 필수적인 기능이 지원되지 않거나 구현 자체에 버그나 에러가 있는 결함이 있을 수도 있으므로 합리적인 방법을 통해 이러한 문제를 우회하라. 특정 기기에서만 우회하거나  특정 기기에만 제한을 두는 방법은 권장되지 않는다.

4. [테스트] 에뮬레이터는 물론 실제 디바이스에서도 테스트하라.

5. [URI] 사이트에 진입하는 URI는 짧게 만들어라.

6. [탐색바] 페이지 상단에는 최소한의 탐색 메뉴만 제공하라.

상단에는 기본적인 메뉴만 제공하고 정말 필요하다면 페이지 하단에 추가 메뉴를 제공하라. 사용자는 페이지를 읽어들였을 때 스크롤하지 않고도 콘텐츠를 볼 수 있어야 한다.

7. [균형] 한 페이지에 너무 많은 링크를 포함시키는 것과 어떤 콘텐츠에 접근하기위해 링크를 너무 많이 이동해야 하는 것은 서로 트레이드 오프 관계이므로 적절히 조절하라.

8. [탐색] 일관성있는 탐색 메커니즘을 제공하라.

9. [키보드 접근] 탐색 메뉴의 링크와 자주 사용하는 기능에 접근할 수 있는 단축키를 제공하라.

10. [링크 대상 ID] 각 링크의 대상을 명확히 설정하라.

11. [링크 대상 형식] 해당 디바이스가 대상 파일을 지원하는지 정확히 알 수 없다면 대상 파일의 형식을 고지하라.

테스트 방법

- 휴먼 테스트 : 링크에 적절한 설명이 제공되는가 (예. "여기를 클릭하세요"는 안됨)
- 머신 테스트 : 링크가 HTML이 아닌 형식을 가리키는가
- 휴먼 테스트 : 만약 HTML이 아닌 형식을 가리킨다면 이 링크 대상의 형식에 대한 정보가 적절히 제공되는가

12. [이미지맵] 디바이스가 이미지맵을 효과적으로 지원하는지 정확히 알 수 없다면 이미지맵을 사용하지 마라.

13. [팝업] 사용자에게 알리지 않고 팝업이나 새 창을 띄우지 말고, 현재 창을 변경하지 마라.

14. [자동 새로고침] 사용자에게 알리지 않고, 멈출 수단도 만들지 않은 상태에서 주기적으로 페이지를 자동으로 새로 고침하도록 만들지 마라.

15. [리디렉션] 다른 페이지로 자동으로 이동하는 마크업을 사용하지 마라. 필요하다면 서버에서 HTTP 3xx 코드를 반환하여 리디렉션하라.

16. [외부 리소스] 링크한 외부 리소스의 개수를 최소한으로 유지하라.

17. [적합성] 모바일 환경에서 사용하기 적합한 콘텐츠가 되도록 하라.

18. [명료성] 분명하고 간결한 말을 사용하라.

19. [제한] 콘텐츠는 사용자가 요청한 것으로만 제한하라.

모바일 사용자는 트래픽에 돈을 지불하므로 관련 없는 콘텐츠를 너무 많이 제공하면(특히 광고) 사용자의 시간과 돈을 소비하게 되어 결과적으로는 불만족스러운 사용자 경험을 낳는다. 일반적으로 이러한 콘텐츠는 다운로드 하기 전에 사용자의 동의를 구하는 것이 좋다.

20. [유용한 페이지 크기] 페이지를 유용하지만 제한된 크기로 나누어라.

21. [페이지 크기 제한] 페이지의 전체 크기가 디바이스의 제한된 메모리에서도 문제없는지 확인하라.

22. [스크롤링] 불가피한 경우를 제외하고, 스크롤은 한 방향으로 제한하라.

가로 혹은 세로 중 하나만 사용하라. 어쩔 수 없는 경우는 예외로 한다.

23. [중심 의미] 페이지의 중심 의미에 해당하는 글감을 그렇지 않은 글감보다 앞에 나오도록 작성하라.

가장 중요한 정보 혹은 관련있는 정보가 먼저 나타나도록 하라.

24. [공백 그래픽] 그래픽을 사용해 공백을 표현하지 마라.

25. [큰 그래픽] 모바일 디바이스에서 표현할 수 없는 이미지를 사용하지 마라. 필수적인 이미지인 경우를 제외하고 대형 혹은 고해상도 이미지의 사용을 피하라.

26. [색상 사용] 색상을 사용한 정보는 색상을 사용하지 않는 경우에도 알 수 있는지 확인하라.

27. [색상 대비] 전경색과 배경색은 서로 적절한 수준의 대비를 이루어야 한다.

28. [배경 이미지 가독성] 배경 이미지를 적용할 때는 이 상태에서도 디바이스에서 콘텐츠를 읽을 수 있는지 확인하라.

29. [페이지 제목] 짧지만 페이지의 내용을 설명할 수 있는 제목을 사용하라.

30. [프레임 금지] 프레임을 사용하지 마라.

31. [구조] 마크업 언어의 특성을 사용하여 논리적 문서 구조를 표현하라.

32. [테이블 지원] 디바이스에서 테이블을 지원하는지 확실하지 않아면 테이블을 사용하지 마라.

33. [중첩 테이블] 중첩 테이블을 사용하지 마라.

34. [테이블 레이아웃] 테이블을 사용해 레이아웃을 구성하지 마라.

35. [테이블 대안] 가능하다면 다른 수단을 사용해 표 형식을 표현하라.

36. [대체 텍스트] 텍스트가 아닌 콘텐츠에 대해서는 항상 그에 상응하는 텍스트를 제공하라.

37. [오브젝트 혹은 스크립트] 내장 오브젝트나 스크립트에 의존하지 마라.

38. [이미지 크기] 크기가 정해진 이미지는 마크업에서 이미지 크기를 설정하라.

39. [이미지 리사이즈] 이미지 크기가 정해져 있다면, 이미지 리사이즈는 서버에서 하라.

40. [유효한 마크업] 문서는 유효한 문법을 사용해 작성하라.

41. [단위] 마크업 언어의 속성이나 스타일 속성의 값에서 픽셀 단위 혹은 절대 단위를 사용하지 마라.

42. [스타일시트 사용] 디바이스가 CSS를 제공하는지 명확하지 않은 경우가 아니라면, 레이아웃과 프리젠테이션은 스타일 시트를 사용해 제어하라.

43. [스타일시트 지원] 필요에 따라 스타일 시트없이도 문서가 잘 보이도록 문서를 구조화하라.

44. [스타일시트 크기] 스타일시트의 크기는 작게 유지하라.

45. [최소화] 간결하고 효율적인 마크업을 사용하라.

46. [콘텐츠 형식 지원] 디바이스에서 지원하는 것이 확실한 형식으로 콘텐츠를 전송하라.

47. [콘텐츠 형식 선호] 가능하다면 디바이스에서 선호하는 형식으로 콘텐츠를 전송하라.

48. [문자 인코딩 지원] 디바이스에서 지원하는 것이 확실한 문자 인코딩을 사용해 콘텐츠를 인코딩하라.

49. [문자 인코딩 사용] 응답시 사용한 문자 인코딩을 명시하라.

HTTP 헤더에서는 Content-Type: text/html; charset=utf-8 으로 표현할 수 있고, XML에서는 <?xml version="1.0" encoding="UTF-8" ?> 과 같이 표현할 수 있다.

50. [에러 메시지] 정보가 있는 에러 메시지를 제공하는 한편, 에러 메시지에서 관련 정보로 이동할 수 있는 수단도 제공하라.

51. [쿠키] 쿠키를 항상 사용할 수 있다고 가정하지 마라.

52. [캐싱] HTTP 응답에 캐시 정보를 제공하라.

53. [글꼴] 특정 글꼴과 관련한 스타일에 의존하지 마라.

54. [키 입력 최소화] 키 입력 횟수를 최소화하라.

55. [자유 입력 회피] 가능하다면 자유롭게 입력할 수 있는 텍스트는 피하라.

56. [기본값 제공] 가능하다면 미리 선택된 기본값을 제공하라.

57. [기본 입력 모드] 디바이스에서 지원한다면 기본 텍스트 입력 모드, 언어, 입력 형식 등을 제공하라.

58. [탭 순서] 논리적인 순서로 링크, 폼 컨트롤, 객체를 탐색할 수 있어야 한다.

59. [컨트롤 레이블] 모든 폼 컨트롤은 적절하게 레이블을 추가해야하며, 명확히 관련있는 레이블이 있어야 한다.

60. [컨트롤 위치] 레이블의 위치를 조정하여 연관성있는 폼 컨트롤과 관련있어 보이도록 배치하라.

Posted by 행복한고니 트랙백 0 : 댓글 0

Louis HarboeiOS 4 아이콘을 CSS만으로 만들었습니다. 그의 작품을 볼 수 있는 것은 물론, 아이콘을 그리기 위해 사용한 높은 수준의 아이디어를 들어볼 수도 있습니다.
연락처 아이콘에서 사람의 실루엣을 그리기 위해 5개의 도형을 사용했습니다. 머리는 둥근 모서리를 가진 사각형으로, 목은 사각형으로, 몸은 약간 찌그러뜨린 반원으로 표현했습니다. 어깨에서 목으로 이어지는 선을 표현하기 위해 원 두개를 그 위에 겹쳤습니다.
날씨 아이콘에는 해의 뒤편에서 나오는 여러 갈래의 햇살이 있습니다. 햇살은 양 끝단으로 갈수록 투명해지는 그래디언트 배경색이 적용된 긴 사각형으로 표현했습니다. 사각형의 각기 다른 각을 표현하기 위해 -webkit-transform:rotate를 사용했습니다. 같은 효과를 iTunes 아이콘에도 적용했습니다.
iDisk 아이콘의 구름 아이콘을 그리기 위해 둥근 모서리 사각형 위에 두 개의 원을 겹쳐 표현했습니다. 큰 원은 사각형 바로 앞에서 멈추는 그래디언트 배경색을 가지고 있습니다.
달력을 표현하기 위한 전체 소스는 다음과 같습니다.
[code:css]
.calendar {
        background: #9B2424;
}
.calendar .header {
        -webkit-border-top-left-radius: 30px;
        -webkit-border-top-right-radius: 30px;
        background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#EEC4C4), to(#521B1C), color-stop(.92,#da3434),color-stop(.1,#ef9fa5));
        height: 50px;
        width: 176px;
        -webkit-box-shadow: inset 0px 2px 1px rgba(255, 255, 255, 0.4);
}

.calendar p.weekday {
        color: #fff;
        font-weight: bold;
        text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.7);
        width: 176px;
        line-height: 50px;
        font-size: 25px;
        text-align: center;
}

.calendar p.daynumber {
        color: #000;
        font-weight: bold;
        text-shadow: 0px 1px 0px #fff;
        width: 176px;
        line-height: 126px;
        font-size: 130px;
        text-align: center;
}

.calendar .paper {
        -webkit-border-bottom-left-radius: 30px;
        -webkit-border-bottom-right-radius: 30px;
        background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#7A7A7A), to(#EDEDED), color-stop(.05,#BFBFBF),color-stop(.2,#E3E3E3));
        height: 126px;
        width: 176px;
}
멋지죠? 이 방법의 장점은 크기를 자유자재로 조절할 수 있다는 것입니다. 벌써 아이폰 4 사용자들 사이에서는 저해상도 아이콘에 대한 불만이 나타나고 있습니다. 심지어 페이스북 앱이라 해도... 텍스트는 정말 훌륭하지만 아이콘은 투박합니다.

이 외에 또 다른 CSS 그래디언트 예제를 소개할까 합니다. 아이콘, 버튼, 진행상태바 등을 CSS로 표현했습니다.

from Made In CSS; iOS icons and more
Posted by 행복한고니 트랙백 1 : 댓글 1
지난 22일에 파이어폭스의 새 버전이 나왔습니다. 여전히 버전은 3.6 대이지만, 3.7 에서 도입하려고 했던 플러그인 오류 보호 시스템이 포함되었습니다(크롬 브라우저의 그것과 유사합니다).

오류 보호 기능은 플러그인을 자신만의 프로세스로 분리합니다. 즉, 플러그인이 비정상적으로 종료되거나 멈추더라도 브라우저 전체에 영향을 미치지는 않게 됩니다. 모질라 의하면 브라우저가 죽는 원인의 1/3 이 써드파티 플러그인 때문입니다.

현재는 리눅스와 윈도우즈 버전에만 오류 보호 기능이 포함되어있으며, 맥 사용자들은 올해 말쯤에 출시될 파이어폭스 4까지 기다리셔야 합니다. 버전은 아주 조금 바뀌었는데, 정말 좋은 기능이 포함되었습니다.

from Firefox joins Chrome in plugin crash protection
Posted by 행복한고니 트랙백 2 : 댓글 1
구글의 Chrome and HTML DevRel 팀에서 HTML5에 대한 좋은 자료들을 모아놓은 HTML5Rocks라는 새로운 포탈을 선보였습니다.

현재 이 사이트는 HTML5 자체에 대해 설명하는 여러 자료는 물론, 브라우저 지원확인해볼 수 있는 링크나 스크립트, 오래된라우저를 위한 HTML5 지원 스크립트 등을 포함합니다.

리소스 외에도, 멋진 HTML5 슬라이드 프리젠테이션과 바로 실험해볼 수 있는 코드 놀이터도 있습니다. 슬라이드는 이전에 APIRocks에서 선보였던 것과 동일합니다.

많은 양의 좋은 자료가 한 곳에 모여있습니다. 이제 막 선보인 점을 감안하면, 곧 더 많은 내용이 추가될 것이라 생각합니다.

from HTML5Rocks.com: Google DevRel shares the love
Posted by 행복한고니 트랙백 2 : 댓글 2
돋보기 보는 사람

http://www.flickr.com/photos/andercismo/2349098787/


Jack Prosser가 재밌는 CSS 돋보기를 만들었습니다.
주요 컨셉은 CSS의 radius를 사용해서 동그라미 모양의 뷰 영역을 만드는 것입니다. 이 영역은 현재 페이지와 똑같은 컨텐트를 가진 iframe을 포함합니다. CSS3를 사용해서 iframe 내부의 컨텐트를 2배 확대해서, 작은 컨텐트를 읽기 편하게 만들었습니다. 이 돋보기는 간단한 키보드 조합으로 보이고/감추고 축소/확대를 할 수 있습니다. 앞으로는 구글 크롬이나 Firefox 확장기능을 만들 생각입니다. 확장기능은 iframe을 사용하지 않고, 페이지 컨텐트에 캔버스를 사용할 생각입니다. 물론, 페이지 컨텐트가 업데이트되면 캔버스도 업데이트 될 것입니다.
실제 동작을 보세요:


from MagnifyMa : A CSS magnifying glass
Posted by 행복한고니 트랙백 2 : 댓글 1

CSS calc()

2010.06.16 08:40 from [IT] Web Tech

CSS에서 상대적인 크기 계산을 위해 자바스크립트를 사용해본 기억이 있을 것입니다. 예를 들어, '절반(50%)에서 5px 뺀 너비' 등과 같이 말이죠. 하지만, 이젠 그럴 필요가 없게 됐습니다.

Paul Roget씨가 CSS calc()에 대해서 설명해주셨습니다. CSS calc()는 아직 버그가 있는 상태입니다.

다음은 간단한 사용예입니다.
[code:css]
/*
* Two divs aligned, split up by a 1em margin
*/
#a {
  width:75%;
  margin-right: 1em;
}
#b {
  width: -moz-calc(25% - 1em);
}
/*
 * Make sure input field won't overlap parent
 */
input {
  padding:2px;
  border:1px solid black;
  display:block;
  width: -moz-calc(100% - 2 * 3px);
}

/*
 * combine different units!
 */

width: -moz-calc(3px + 50%/3 - 3em + 1rem);
이 덕분에 상당히 많은 자바스크립트를 줄일 수 있게 되었습니다. 하지만, Firefox에서만 가능한 방법이라 실무에 적용하기는 다소 어려울 듯 합니다. ^^;

from CSS calc() in the house
Posted by 행복한고니 트랙백 1 : 댓글 2

영화 '아멜리에' 중


IE6는 사라져야 합니다. 우리 모두 그 사실을 알고 있고, 심지어 MS조차 이를 인정했습니다(IE9 팀은 업그레이드를 권장했습니다). 문제는 이게 기술적인 수준의 논의에서만 그친다는 것입니다.

어떤 사람들은 고객들에게 사용 환경을 바꾸지 말고 계속 IE6를 메인 브라우저로 쓰도록 강요합니다. 사용 환경이 바뀌면 수천대의 컴퓨터를 업그레이드 해줘야하고, 새 시스템의 컴퓨터를 좋아하지 않는 고객을 다시 교육 시켜야 하기 때문입니다. 이게 바로  이러한 조직이 IE6 때문에 문제가 생길 수 있는 방법을 찾아야 하는 이유입니다. 

이런 이유에서 저는 IE6 사용자들에게 짜증을 유발할만한 방법을 연구했고, MotionBlur() 필터라는 해답을 얻었습니다. 몇 초마다 한번씩 이 필터를 적용하면 IE6 사용자들은 매우 괴이한 경험을 하게 될 것입니다.

소스 코드는 다음과 같습니다. 홈페이지에서 다운로드 할 수도 있습니다.
[code:js]
if(document.all && !window.XMLHttpRequest){
var x = 1,when=0,str,dir,fil;
function amelie(){
  if(x % 2 === 0){
    str = 0; dir = 0;
    when = Math.floor( Math.random() * 10000 ) + 2000;
    setTimeout( 'amelie()', when );
  } else {
    str = Math.floor( Math.random() * 2 ) + 2;
    dir = Math.floor( Math.random() * 360 );
    setTimeout( 'amelie()', 500 );
  }
  var fil = "progid:DXImageTransform.Microsoft.MotionBlur(strength="+ 
            str + ",direction=" + dir + ",enabled='true')";
  document.body.style.filter = fil;
  x++;
}
setTimeout('amelie()',1000);
}
이 코드를 사이트에 적용하면 IE6 사용자들이 불평할 것입니다. 그 때가 바로 우리의 계획을 실행할 때입니다.
  1. amelie()를 웹 사이트에 적용합니다.
  2. 사용자들이 불평하면 우리 코드는 괜찮으며 아무 문제없다고 합니다. (필요하다면 빌드 테스트 로그라도 보여주세요)
  3. 전문가를 포섭해 "소프트웨어 피로"의 개념에 대해 말하게 합니다. '소프트웨어 피로'란 소프트웨어도 기계와 마찬가지로 시간이 지남에 따라 기능이 약화되며 가끔 에러를 일으킬 때도 있다는 순도 100%의 거짓말입니다. 소프트웨어의 일부가 톱니바퀴처럼 조금씩 소모된다는 것이죠. 이 방식은 의외로 잘 먹힙니다. 저는 사람들에게 컴퓨터를 끈 후에는 리부팅하기전에 '모든 칩이 메모리에서 해제되려면' 15분 정도 기다려야 한다고 말하곤 했습니다.  
  4. IE6의 소프트웨어 피로때문에 그래픽 카드와 호환성의 문제가 있다는 루머를 퍼트립니다. 호환성 문제때문에 자잘한 화면 표시 문제가 나타난다고 하는 겁니다. 
  5. 이제 IE6 자체에 안정성 문제가 있는 것으로 만들었습니다. 안정성 문제 때문에 기업에서는 기술적인 문제로 환경을 바꿔야 할 때보다 더 빨리 움직일 것입니다.
너무 진지하게 보지는 마세요 :)

from amelie() - a devious plan to get rid of IE6
Posted by 행복한고니 트랙백 3 : 댓글 0
Thomas Frank 씨가 배열과 객체에 SQL과 유사한 문법의 질의를 하고, 데이터를 추출할 수 있는 SQLike 스크립트를 작성했습니다.
질의는 다음과 같이 할 수 있습니다.
[code:js]
SQLike.q(
    {
        Select: ['firstName','|count|','firstName','|sum|','salary','|min|','salary','|max|','salary','|avg|','salary'],
        From: dataArray,
        GroupBy: ['firstName'],
        Having: function(){return this.count_firstName>1},
        OrderBy: ['sum_salary','|desc|']
   }
)
결과는 다음과 같이 반환됩니다.
[code:js]
[{"firstName":"Stuart", "count_firstName":3, "sum_salary":180000, "min_salary":41000, "max_salary":90000, "avg_salary":60000}, {"firstName":"Vicki", "count_firstName":2, "sum_salary":163000, "min_salary":79000, "max_salary":84000, "avg_salary":81500}]
이 모든 과정은 메모리 상에서 일어나기 때문에 웹 서비스로서 비슷한 기능을 제공하는 YQL과는 조금 다릅니다.
SQL 질의를 할 수 있는 다른 방법으로는 Chris Pietschmann씨가 작성한 LINQ to JavaScript가 있습니다.
[code:js]
var myList = [
  {FirstName:"Chris",LastName:"Pearson"},
  {FirstName:"Kate",LastName:"Johnson"},
  {FirstName:"Josh",LastName:"Sutherland"},
  {FirstName:"John",LastName:"Ronald"},
  {FirstName:"Steve",LastName:"Pinkerton"}
];
var exampleArray = JSLINQ(myList)
                   .Where(function(item){ return item.FirstName == "Chris"; })
                   .OrderBy(function(item) { return item.FirstName; })
                   .Select(function(item){ return item.FirstName; });
개인적으로는 LINQ의 문법이 더 마음에 듭니다. 여러분은 어떠세요?

from Two JS solutions to run SQL-like statements on Arrays and Objects
Posted by 행복한고니 트랙백 2 : 댓글 0

Sergey Chernyshev씨와 그의 팀이 작성한 Show SlowYSlow와 Page Speed를 사용해 페이지 속도를 모니터링합니다.
Show Slow는 YSlow와 Page Speed를 여러분의 사이트에 사용하고, 매일 통계를 수집합니다. 여러분이 할 일은 가만히 앉아서 그래프를 보는 것뿐입니다!
지금 Alexa 상위 100개 사이트의 점수를 볼 수 있습니다.

매우 좋은 유틸리티입니다. 한번 써보세요~

from ShowSlow monitors your YSlow and Google Page Speed scores
Posted by 행복한고니 트랙백 1 : 댓글 0

Greg Murray씨가 HTML5 Fish Tank라는 재밌는 예제 프로그램 베타판을 작성했습니다. 이 프로그램은 사용자가 자신만의 물고기를 만들고, 만든 물고기를 어항에 놓을 수 있는 프로그램입니다.
또한, 이 프로그램에는 저수준(low level)의 Canvas와 CSS3 전이/변형 효과가 사용되었습니다.
[code:js]
<div id="1275463173677" class="fish" style="-webkit-transition-duration: 3369ms; -webkit-transform-origin-x: 508px; -webkit-transform-origin-y: 485px; -webkit-transform: rotateY(0deg) translate(508px, 485px); ">
    <div style="position: absolute; margin-top: 27px; margin-left: 70px; "><canvas width="30" height="44" style="width: 30px; height: 66px; "></canvas></div>
    <div style="position: absolute; margin-top: 25px; margin-left: 2px; "><canvas width="71" height="71" style="width: 71.5px; height: 71.5px; "></canvas></div>
    <div style="position: absolute; margin-top: 40px; margin-left: 19px; "><canvas width="20" height="20" style="width: 20px; height: 20px; "></canvas></div>
    <div style="position: absolute; margin-top: 59px; margin-left: 4px; "><canvas width="44" height="44" style="width: 44px; height: 44px; "></canvas></div>
    <div style="position: absolute; margin-top: 45px; margin-left: 40px; "><canvas width="20" height="20" style="width: 20px; height: 20px; "></canvas></div>
    <div style="position: absolute; margin-top: 19px; margin-left: 26px; "><canvas width="33" height="33" style="width: 33px; height: 33px; "></canvas></div>
    <div style="position: absolute; margin-top: 81px; margin-left: 40px; "><canvas width="44" height="44" style="width: 44px; height: 44px; "></canvas></div>
</div>
물고기의 애니메이션은 다음과 같이 작성되었습니다.
[code:js] function goFish( target) {         if ( !target.lastPoint) {             target.lastPoint = target.currentPoint;         }         if ( target.timer ) {             clearTimeout(  target.timer );         }         target.currentPoint = getRandomPoint();         target.style.webkitTransitionDuration = target.currentPoint.d;         target.style.webkitTransformOrigin = target.currentPoint .x + " " + target.currentPoint.y;         var _scale = "";         if ( target.lastPoint.x> target.currentPoint.x ) {             _scale = "rotateY(-180deg)";         } else {              _scale = "rotateY(0deg)";         }          target.style.webkitTransform =  _scale + " translate(" + target.currentPoint.x + "px, " + target.currentPoint.y + "px)";         target.lastPoint = target.currentPoint;         target.timer = setTimeout( function () {             console.log( "saved the day" );             goFish( target);         },  ( target.currentPoint.d + 2000 ) ); }

from Build a Fish Tank with Canvas and CSS3
Posted by 행복한고니 트랙백 2 : 댓글 2
Chris Vanrensburg: “최근의 위치 변경 애니메이션의 연장선 상에서, 저는 객체의 크기가 변함에 따라 곡선이 어떻게 적용되는지 보고 싶었습니다. 예상대로 너비와 높이 CSS 스타일 속성에 여러가지 곡선을 적용해보는 것은 꽤 재미있는 효과를 만들어냈습니다.”
웹 2.0 진영에서는 둥근 모서리가 사랑받고 있습니다. 그런데 애니메이션이라니요! 이 애니메이션은 Chris의 최근 실험에서 확인할 수 있습니다. 클릭해서 데모와 부드러운 효과를 살펴보세요.


from Round Corners. Moving.
Posted by 행복한고니 트랙백 1 : 댓글 0
인터넷 회선을 선택할 때, 네트웍 대역폭을 기준으로 하는 편이 이해하기 쉽습니다. "5Mbps 이상으로 해주세요!". 물론, 대역폭이 중요하긴 하지만 성능이 대역폭만으로 결정되지는 않습니다. 더군다나 HTTP처럼 짧고 잦은 접속이라면 대역폭보다는 응답시간(RTT : Round-Trip Time)이 성능에 더 중요합니다.
이는 구글의 Mike Belshe씨가 작성한 글이며, 이에 대한 상세 보고서도 있습니다.
대역폭 속도는 "더 빠른 대역폭 == 더 좋다"고 알려져있었습니다. 사실, 다른 많은 일들과 마찬가지로 여기에는 많은 변수가 있습니다. 대역폭이 증가할수록 대역폭의 중요성은 점점 감소하고, 다른 요소가 더 중요해집니다.
위에서 보듯 응답시간이 훨씬 중요합니다.
사용자가 대역폭을 두 배로 늘려도 응답시간을 도드라지게 줄이지 못했다면, 웹 브라우징 속도 개선 효과는 미미할 것입니다. 그러나 응답 시간을 줄이면, 현재의 대역폭과는 상관없이 웹 브라우징 속도는 더 빨라집니다. 인터넷 속도를 많이 빠르게 만들려면, 응답시간을 더 줄일 방법을 찾아야 합니다. 만약 응답속도를 150ms에서 100ms까지 줄일 수 있다면 사용자의 대역폭을 3.9Mbps에서 10Mbps 또는 1Gbps로 늘린 것과 같은 효과를 볼 수 있습니다.

from More Bandwidth Doesn't Matter Much (Above ~5Mbps)
Posted by 행복한고니 트랙백 1 : 댓글 0

http://www.flickr.com/photos/florisla/1943594953/

WebM 프로젝트는 누구나 자유롭게 사용할 수 있는 고품질의 오픈된 웹 비디오 포맷을 개발합니다.
모질라, 구글, 오페라를 비롯한 40여개 이상의 컨텐츠 배포자, 소프트웨어 및 하드웨어 제작사들이 WebM을 지원합니다.
WebM은 웹을 위한 오픈 소스의 로열티가 없는 미디어 포맷입니다.
WebM은 파일 컨테이너 구조와 비디오, 오디오 포맷을 정의합니다. WebM 파일은 VP8 비디오 코덱을 사용한 압축된 비디오 스트림과 Vorbis 오디오 코덱을 사용한 압축된 오디오 스트림으로 구성됩니다. WebM 파일 구조는 Matroka 컨테이너를 기반으로 합니다.
구글이 I/O 에서 다수의 파트너들(브라우저에서는 오페라와 모질라가 참여)과 함께 새로운 WebM 프로젝트를 공개했습니다. WebM 프로젝트는 구글이 인수했던 On2의 코덱을 사용합니다. 이 발표는 개방형 비디오 전쟁에 있어 큰 뉴스이며, 이제 모두의 눈은 사파리로 향하게 되었습니다.

WebM 프로젝트는 다음과 같은 목표를 가지고 있습니다.
  • 개방과 혁신. 웹이 성공할 수 있었던 주요 요인은 HTML, HTTP, TCP/IP 와 같은 핵심 기술들이 누구나 구현하고 개선할 수 있도록 개방되어있다는 것이었습니다. 동영상이 웹 경험의 중심이 되어가면서 고품질의 개방된 비디오 포맷이 필요해졌습니다. WebM은 100% 무료인, BSD 유사 라이센스를 가진 오픈 소스 프로젝트입니다.
  • 웹에 최적화. 웹에서 동영상을 제공한다는 것은 전통적인 방송이나 오프라인 미디어와는 다릅니다. 현존하는 비디오 포맷들은 이러한 미디어들의 필요를 충족시키기 위해 고안되었고, 그 목적에 맞게 잘 동작합니다. WebM은 웹에서의 동영상 제공이라는 독특한 필요를 충족시키는 것에 집중했습니다.
    • 넷북, 모바일 장치, 타블렛 등의 어떤 장치에서도 재생할 수 있도록 적은 계산
    • 단순한 컨테이너 포맷
    • 최고 품질의 실시간 비디오 전송
    • 쉬운 인코딩. 최소한의 코덱 프로필과 부가 옵션. 가능하다면, 어려운 결정을 인코더에 위임
* 주의 : WebM을 지원하는 브라우저의 초기 개발자 버전은 아직 완전히 최적화되지 않았습니다. 따라서, 스크린 렌더링을 위해 정상적인 릴리스에 기대했던 것보다는 많은 계산을 요구합니다. WebM의 계산 효율성은 VP8 SDK의 개발자 도구를 통해 보다 정밀하게 측정할 수 있습니다. 브라우저에서의 최적화는 앞으로 이루어질 예정입니다.

개방형 웹에 축하를!

FlashIE9에서도 VP8 코덱을 지원하기로 했습니다. 당연하겠지만, 이제 모두의 관심은 애플의 사파리로 모이고 있습니다. :)

from WebM : The On2 codec is here, with support from Google, Mozilla, and Opera
Posted by 행복한고니 트랙백 1 : 댓글 0

http://www.flickr.com/photos/jonathasrr/4195103621/


초기의 HTML 스펙에는 HTML 요소에 대한 기본 스타일이 주어지지 않았었습니다. 당연히 브라우저 제작사들에게도 이런 가이드가 없었습니다. body는 마진(margin)이나 패딩(padding)값을 가질까요? 색상은요?

여러 브라우저를 다룰 때 사용할 수 있는 방법 초기에는 모든 브라우저에 대해 CSS를 초기화한 후, 그 뒤에 스타일을 작성했습니다. 이 방법에는 에릭 마이어의 초기화YUI 초기화 등이 있습니다.

블라디미르 까레르는 80% 정도의 규칙을 다루는 자신의 미니 초기화를 공개했습니다.
[code:css] html, body, div, form, fieldset, legend, label {  margin: 0;  padding: 0; } table {  border-collapse: collapse;  border-spacing: 0; } th, td {  text-align: left;  vertical-align: top; } h1, h2, h3, h4, h5, h6, th, td, caption { font-weight:normal; } img { border: 0; }
아주 작은 초기화를 제안한 사람들도 있었습니다.
[code:css] * { vertical-align: baseline; font-weight: inherit; font-family: inherit; font-style: inherit; font-size: 100%; border: 0; padding: 0; margin: 0; }
어떤 초기화를 사용하시나요?

from CSS Structural Reset
Posted by 행복한고니 트랙백 1 : 댓글 0

CCL source from http://www.lightmatterphotography.com/


FireBreath 1.0 이 릴리스 되었습니다. 이게 뭘까요?
FireBreath는 크로스 플랫폼 플러그인 아키텍쳐로, 다음을 목표로 합니다.
  • NPAPI 브라우저 지원(윈도우, 맥, 리눅스):
    • Gecko/파이어폭스
    • 구글 크롬
    • Apple 사파리
  • ActiveX 콘트롤 호스트 :
    • Microsoft 인터넷 익스플로러 6, 7, 8
새로 작성한 플러그인에서 스크립트를 실행하고 다양한 기능을 더하거나 수정할 수 있습니다. Indexed DB와 같은 W3C API를 구현해보는 것도 재밌을 것 같습니다.

from FireBreath: Cross platform plugin framework
Posted by 행복한고니 트랙백 1 : 댓글 0
최근의 웹에서 동영상과 동영상 포맷에 대한 글이 많이 늘었습니다. 지금이 Microsoft의 관점을 이야기할만한 좋은 기회가 아닌가 합니다.

웹의 미래는 HTML5입니다. Microsoft는 W3C와 함께 HTML5의 진행에 깊이 관여하고 있습니다. HTML5는 발전하는 풍부한 인터랙티브 웹 응용프로그램과 사이트 디자인에 매우 중요해질 것입니다. HTML5 명세는 동영상을 지원하는데, 특정한 동영상 포맷을 정하지는 않았습니다. 우리는 H.264가 훌륭한 포맷이라고 생각합니다. HTML5를 지원하는 IE9은 H.264 동영상 재생만을 지원합니다.

H.264는 산업 표준으로서 폭넓고 강력한 하드웨어 지원이 뒷받침됩니다. 이러한 표준화 덕분에 여러분은 손쉽게 일반적인 비디오 카메라로 녹화한 동영상을 웹에 올리고, H.264를 지원하는 운영체제(예. Windows 7을 설치한 PC)의 웹 브라우저에서 재생할 수 있습니다. 최근에 우리는 IE9에서 H.264로 인코딩된 유튜브 동영상을 재생해 보인 바 있습니다. 하드웨어 가속의 이점은 여기서 읽을 수 있으며, 혹은 이 강연의 26:35쯤부터 장점의 사례를 볼 수 있습니다.

다른 코덱들도 종종 비교되고는 합니다. 소스 코드를 사용할 수 있다는 것과 소스 코드의 지적재산권을 소유하는 것은 서로 다른 문제입니다. H.264의 지적재산권은 MPEG LA의 프로그램을 통해 잘 관리되고 있으므로, 소스 코드를 광범위하게 사용할 수 있습니다. 반면, 다른 코덱들의 지적재산권은 언론에서 알려진 바와 같이 명확하지 않습니다. 물론, Windows 7과 같은 운영체제의 하드웨어 가속 지원과 H.264 코덱을 사용하려는 개발자들은 아무런 로열티를 제공하지 않아도 됩니다.

오늘날, 웹에서는 플래시 기반의 동영상이 우세합니다. 다른 포맷으로도 동영상을 볼 수 있긴 하지만, 일반 사용자들에게는 플래시만큼 편한 방법도 없습니다. 플래시는 신뢰성, 보안성, 성능 등의 문제가 있습니다. 우리는 Adobe 기술자들과 긴밀히 일하며, 이러한 문제들에 대한 정보도 공유하고 있습니다. 이러한 문제에도 불구하고, 오늘날의 웹에서 플래시가 좋은 사용자 경험을 전달하는데 중요한 위치를 차지한다는 사실은 부정할 수 없습니다.

Dean Hachamovitch
General Manager, Internet Explorer

from HTML5 Video (IEBlog)
Posted by 행복한고니 트랙백 1 : 댓글 0
현재의 웹은 어떻게 흘러가고 있을까요? 존 얼솝(John Allsopp)씨가 웹 개발 현황 2010 최신 설문조사 결과와 함께 돌아왔습니다.
이 어마한 양의 데이터는 직접 받아볼 수 있으며, 전체 보고서는 PDF로 볼 수 있습니다.

보고서에서 주목할만한 부분을 간추려봤습니다.
  • 소수의 응답자만이 인터넷 익스플로러를 일상적으로 사용하지만, 사이트를 테스트할 때는 IE8을 가장 많이 사용했습니다.
  •  구글 크롬이 극적으로 성장해 개발자들이 사용하는 브라우저 3위로 자리잡았습니다. 20%인 사파리를 17%로 바짝 추격하고 있습니다.
  • 파이어폭스가 여전히 1위 자리를 지키고 있지만, 응답자들의 브라우저는 3.5와 3.6으로 나누어졌습니다.
  • 파이어폭스 3.6은 설문조사를 실시하기 1주일 전에 출시되었습니다.
  • 절반 이상의 응답자들이 맥 OS X를 주 운영체제로 사용했습니다.
  • 응답자들의 1/3 정도(16%)가 모바일 사파리를 사용하는 반면, 안드로이드는 4%에 그쳤습니다.
  • jQuery의 독주는 더 강화되었습니다. 80%에 가까운 응답자들이 라이브러리로 jQuery를 사용했습니다. 작년에는 63% 였습니다.
  • Cappuccino나 SproutCore와 같은 데스크톱스러운 응용프로그램 프레임워크들이 개발자들에게 조금씩 퍼지고 있는 것처럼 보입니다. 데스크톱스러운 응용프로그램의 시대가 아직 오지 않은 것일 수도 있고, 개발자들이 데스크톱 흉내를 낸 웹 응용프로그램을 만들고 싶어하지 않는 것일 수도 있습니다.
웹 기술 쪽에서의 화두는 역시 HTML5, CSS3, 웹폰트 등이었습니다.
  • 다수의 응답자들(45%)이 CSS3나 실험적인 CSS를 사용했습니다. 사용하지 않는 비율은 44%입니다. 이는 작년에 비해 극적으로 증가한 수치입니다(작년에는 22%가 CSS3 사용, 70%가 사용하지 않음).
  • 바로 전 설문조사에서는 4%의 응답자만이 @font-face를 사용한 웹 폰트를 적용했었는데, 이번 조사에서는 23%로 증가했습니다.
  • 응답자의 30%가 HTML5를 사용하는데, 바로 전 설문조사에서는 10%이하였습니다.
재밌는 결과네요. 데이터에서 또 다른 트렌드를 알 수 있나요?

from The State of Web Development 2010 - Web Directions
Posted by 행복한고니 트랙백 1 : 댓글 2