퀴즈로 풀어보는 CSS z-index 속성의 3가지 포인트

웹 페이지가 다이나믹해지고 요소들의 배치가 자유로워지면, 때때로 서로의 위치가 겹치는 요소들이 생기기 마련입니다. 이 때 어느 것을 위에 표시할 것인가를 제어하는 CSS 속성이 다름 아닌 z-index입니다. 그만큼 자주 접하게 되는 속성입니다만, 한편으로는 오해하기 쉬운 몇가지 특징을 가진 속성이기도 합니다.

이번 포스팅에서는 z-index에 대한 중요한 포인트를 3가지 퀴즈를 통해 알아봅니다. (이 질문은 제가 신입 개발자들을 교육할 때 실제로 사용하고 있는 질문이기도 합니다.) 이 3가지 질문에 대해 정확하게 답을 하고 원리를 설명하실 수 있다면, 실무에서 만나는 대부분의 상황에서는 z-index 속성을 사용하는 데에는 큰 문제가 없으실 것입니다.

z-index의 정확한 사양에 대해서는 CSS Specification의 9.9.1 Specifying the stack level: the ‘z-index’ property 항목에서 다루고 있습니다. 좀더 자세한 정보가 필요하실 때에 함께 읽어보시기 바랍니다.

 

Q1. CSS가 아래와 같이 작성되어 있을 때, HTML 코드에 있는 3개의 <div>를 상위에 표시되는 순서대로 나열하세요.

#first
{
	z-index		: 30;
	width		: 200px;
	height		: 200px;
	background	: #3366cc;
}
#second
{
	z-index		: 20;
	width		: 200px;
	height		: 200px;
	margin-top	: -100px;
	background	: #cc3333;
}
#third
{
	z-index		: 50;
	width		: 200px;
	height		: 200px;
	margin-top	: -100px;
	margin-left	: 100px;
	background	: #ffaa33;
}
<div id="first">
	1st Box
</div>
<div id="second">
	2nd Box 
	<div id="third">3rd Box</div>
</div>

3개의 <div> 태그가 있습니다. 크기는 모두 가로세로 200픽셀입니다. 2번째와 3번째 <div>는 margin-top 속성이 -100픽셀로 되어 있어, 원래 위치보다 위로 100픽셀 이동하여 보일 것입니다. <div>를 상위에 나오는 순서대로 나열하면 어떻게 될까요?

 

A1. 3rd – 2nd – 1st

z-index 함정퀴즈 #1 정답

많은 분들의 예상과 다르게 정답은 왼쪽과 같습니다. 2nd보다 1st가 z-index 속성에 입력된 값이 더 높기 때문에, 이 정답은 상당히 의외로 느껴질 수 있습니다. 여기에 우리가 기억해야 하는 z-index의 첫 번째 함정이 있습니다.

z-index 값을 지정하기 위해서는 해당 요소의 position 속성이 relative, absolute, fixed 중 하나여야만 한다.

CSS Specification를 살펴보면 z-index 속성의 적용대상은 positioned elements, 즉 position 속성이 설정된 요소로 제한되어 있습니다. 그러나 문제에 등장한 3개의 <div>는 어느 것 하나도 position 속성이 지정되어 있지 않았습니다. 이처럼 position 속성이 지정되지 않은 상태라면, 이 요소들은 z-index가 0인 것처럼 작동합니다. HTML 소스 상에서 나중에 등장하는 요소가 앞에 나온 요소를 덮어버리게 됩니다. 그림을 그릴 때 앞서 칠한 물감을 나중에 칠한 물감이 덮는 것과 같이 말이죠.

 

Q2. CSS가 아래와 같이 작성되어 있을 때, HTML 코드에 있는 3개의 <div>를 상위에 표시되는 순서대로 나열하세요.

#first
{
	position	: relative; 
	z-index		: 30;
	width		: 200px;
	height		: 200px;
	background	: #3366cc;
}
#second
{
	position	: relative; 
	z-index		: 20;
	width		: 200px;
	height		: 200px;
	margin-top	: -100px;
	background	: #cc3333;
}
#third
{
	position	: relative;
	z-index		: 50;
	width		: 200px;
	height		: 200px;
	margin-top	: -100px;
	margin-left	: 100px;
	background	: #ffaa33;
}
<div id="first">
	1st Box
</div>
<div id="second">
	2nd Box 
	<div id="third">3rd Box</div>
</div>

이번 문제에서 등장한 소스코드는 첫 번째 문제의 소스코드에서 각 <div>에 position 속성만 추가로 지정한 것입니다. position 속성은 모두 relative로 설정되었고, top과 left 속성은 지정되지 않았으므로 위치의 변동은 없을 것입니다. <div>를 상위에 나오는 순서대로 나열하면 어떻게 될까요?

 

A2. 1st – 3rd – 2nd

z-index 함정퀴즈 #2 정답이번에야말로 z-index가 큰 순서대로 표시될 것이라고 예상하셨다면, 다시 한 번 예상이 빗나간 결과를 발견하게 됩니다. 우리가 기억해야 하는 z-index의 두 번째 함정이 여기에 있기 때문입니다.

z-index의 값은 같은 depth의 요소끼리 비교하는 것이 원칙이다.

z-index 값은 같은 depth에 있는 형제 요소(Siblings) 간에 비교하여 상하를 결정하는 것이 원칙이며, 자식 요소는 부모 요소의 비교결과를 따라가게 됩니다. 위 코드의 경우에는 형제간인 1st와 2nd를 비교하여 이미 1st가 상위에 있는 것으로 결론내렸기 때문에, 2nd의 자식 요소인 3rd는 아무리 높은 z-index 값을 주어도 1st보다 상위에 표시되지 않습니다.

 

Q3. CSS가 아래와 같이 작성되어 있을 때, HTML 코드에 있는 3개의 <div>를 상위에 표시되는 순서대로 나열하세요.

#first
{
	position	: relative; 
	z-index		: 30;
	width		: 200px;
	height		: 200px;
	background	: #3366cc;
}
#second
{
	position	: relative; 
	/*z-index	: 20;*/
	width		: 200px;
	height		: 200px;
	margin-top	: -100px;
	background	: #cc3333;
}
#third
{
	position	: relative;
	z-index		: 50;
	width		: 200px;
	height		: 200px;
	margin-top	: -100px;
	margin-left	: 100px;
	background	: #ffaa33;
}
<div id="first">
	1st Box
</div>
<div id="second">
	2nd Box 
	<div id="third">3rd Box</div>
</div>

두 번째 문제의 소스코드에서 #second 요소의 z-index 값을 주석처리 하였습니다. 그 외에는 어떠한 변경된 내용도 없습니다. <div>를 상위에 나오는 순서대로 나열하면 어떻게 될까요?

 

A3. 3rd – 1st – 2nd

z-index 함정퀴즈 #3 정답

이 문제의 경우, 1st – 3rd – 2nd라는 오답이 나오기 쉽습니다. 오답의 원인은 바로 z-index의 기본값이 정수 0일 것이라고 잘못 추측하는 데에 있습니다. 우리가 기억해야 하는 z-index의 세 번째 함정은 z-index의 기본값에 관한 것입니다.

z-index의 기본값은 auto이며, 이 경우 브라우저는 그 요소를 제쳐두고 자식 요소의 z-index 값을 비교대상으로 삼는다.

z-index에 아무런 값이 지정되지 않은 경우, 기본값은 auto가 됩니다. z-index가 auto로 지정된 요소는 z-index가 0으로 입력된 것처럼 작동하는 동시에, z-index 값의 비교대상을 자식 요소에게 넘겨줍니다. 위 코드에서는 2nd의 z-index가 auto이므로, 1st와 z-index를 비교할 대상은 3rd가 됩니다. 비교 결과 3rd의 z-index가 1st의 z-index보다 더 높으므로, 결과적으로 3rd가 가장 위에 표시되는 결과를 보게 됩니다.

그렇다면 우리는 왜 z-index의 기본값을 0으로 잘못 알고 있을까요. 이유는 바로 Internet Explorer 7의 버그 때문입니다. 당시 웹 브라우저 시장을 장악하고 있던 IE7에는 한 가지 버그가 있었는데, 그것이 다름 아닌 z-index의 기본값을 auto가 아닌 0으로 지정하는 것이었습니다. 이로 인하여 많은 웹 개발자들에게 잘못된 경험이 축적되었고 지금에 이르게 된 것입니다.

 

정리

금번 포스팅의 내용을 토대로 z-index의 주요 포인트를 정리하면, 아래와 같습니다.

  1. z-index 속성은 대게 정수값을 가지며, 높은 숫자를 가진 요소가 상위에 표시됩니다. 같은 z-index 간에는 HTML 코드상 나중에 등장하는 요소가 상위에 표시됩니다.
  2. z-index 값을 지정하기 위해서는 해당 요소의 position 속성이 relative, absolute, fixed 중 하나여야만 합니다.
  3. z-index의 값은 같은 depth의 요소끼리 비교하는 것이 원칙입니다.
  4. z-index의 기본값은 auto이며, 이 경우 브라우저는 그 요소를 제쳐두고 자식 요소의 z-index 값을 비교대상으로 삼습니다. (단, Internet Explorer 7에서는 z-index의 기본값이 0인 버그가 있습니다.)

코멧(Comet) #3 – Ajax 롱폴링(Ajax Long polling) 채팅방 예제로 배우기

코멧을 구현하는 두 번째 방법은 롱폴링(Long Polling)이라고 하는 기법으로, 그 중에서도 금번 포스팅에서는 Ajax를 기초로 한 롱폴링 기법을 소개합니다. 이것은 지난 포스팅에서 소개한 Ajax 폴링 기법에서 일부분을 변형하여서, HTTP 통신이 일어나는 빈도를 줄인 것입니다. Ajax 폴링과 이 기법 사이의 결정적인 차이점은 서버측에서 특정한 상태값이 변하기 전까지는 응답을 미루는 것이라고 할 수 있습니다.

금번 포스팅에서는 지난 포스팅에서 Ajax 폴링으로 구현한 채팅방 예제를 롱폴링으로 수정하여, Ajax 폴링과 대조되는 롱폴링의 작동원리를 살펴볼 것입니다. 따라서 지난 포스팅을 읽어보지 않은 분께서는 금번 포스팅을 읽기에 앞서 일독을 권합니다.

Continue reading

Epiloum Slider – 간결한 HTML 마크업을 기반으로 하는 jQuery 애니메이션 슬라이더

이번 포스팅에서는 제가 작성한 jQuery 애니메이션 슬라이더(Slider) 모듈인 “Epiloum Slider”를 소개합니다.

웹 상에서 찾을 수 있는 수많은 자바스크립트 또는 jQuery 슬라이더는 필요 이상의 복잡한 HTML 태그 구조를 요구하거나, 사전에 CSS 작업 상당 부분 필요한 경우가 많습니다. 이처럼 애니메이션이라는 UX적인 부분을 위해 마크업을 희생하는 것은 의미론적 마크업의 철학에 위배되는 것이기도 합니다.

Epiloum Slider는 그와 같은 상황에 대한 안타까움으로부터 만들어졌습니다. 본 모듈의 가장 큰 특징은 1개의 <ul> 또는 <ol> 태그와, 그 아래에 나열된 <li> 태그들 만으로 적용 가능하다는 점입니다. 또한 스크립트를 이용해 CSS를 변경하는 일을 최소화하여, 실무에서 응용할 때 레이아웃에 영향을 줄 가능성을 최소화하였습니다. 간결한 마크업를 추구하는 많은 분들께 도움이 되시기를 바라겠습니다.

 

파일구성

아래 버튼을 눌러 다운로드 받은 zip 파일의 압축을 해제하면, 2개의 디렉토리를 만날 수 있습니다. 첫 번째 디렉토리인 Module 아래에는 자바스크립트 파일 epiloum_slider.js이 들어있으며, 실제로 본 슬라이더를 사용할 때에 임베디드해야 하는 파일입니다. 두 번째 디렉토리인 Example 아래에는 본 모듈의 사용예제가 들어 있습니다.

Download Button

Continue reading

Linux에 Django 설치하기

DjangoPython을 언어로 사용하는 웹개발 프레임워크입니다. 금번 포스팅에서는 제가 Linux에서 Django를 설치하고, 첫 프로젝트를 생성했던 과정을 소개하고자 합니다.

금번 설치과정을 거친 서버는 운영체제로 CentOS 6.5를 사용하고 있으며, LAMP 환경의 웹서버가 이미 작동하고 있는 서버였음을 먼저 밝힙니다. 아울러 이 글에서 소개하는 Linux 명령어는 모두 root 계정에서 실행되었음을 첨언하여 두고자 합니다.

Continue reading

코멧(Comet) #2 – Ajax 폴링(Ajax polling) 채팅방 예제로 배우기

코멧을 구현하는 첫 번째 방법은 Ajax 폴링(Ajax Polling)이라고 하는 기법입니다. 이 기법은 모든 코멧 방법론 중에서 가장 직관적이고 구현이 간단하여, 코멧 방법론에 입문할 때에 처음 만나게 되는 기법입니다. 기본적인 아이디어는 일정시간마다 Ajax 통신을 하여 서버의 상태를 가져오는 것이라고 요약할 수 있습니다.

이 포스팅에서는 자바스크립트와 더불어 PHP, MySQL로 구현한 간단한 채팅방 예제를 통해 Ajax 폴링을 구현하는 방법을 알아봅니다.

Continue reading