frontend/css

11. 🧠 CSS z-index와 쌓임 맥락(Stacking Context) 완벽 이해

mirabo01 2025. 11. 5. 21:06

한 번쯤 이런 상황 겪어봤을 거다 👇

“z-index: 9999를 줬는데도 왜 안 올라오지?”

이게 바로 단순한 숫자 문제가 아니라
‘쌓임 맥락(Stacking Context)’ 때문이다.

이번 글에서는 z-index의 동작 원리부터
브라우저가 요소를 어떤 순서로 겹치는지 완벽히 이해하도록 정리했다.


💡 1. z-index란 무엇인가?

“요소가 화면의 앞/뒤 중 어디에 위치할지를 결정하는 속성”

HTML 요소들은 화면 위에 층(layer) 처럼 쌓인다.
이때 어떤 요소가 위로, 어떤 요소가 아래로 갈지를 정하는 것이 z-index.

.box1 { 
  position: relative; 
  z-index: 1; 
} 
.box2 { 
  position: relative; 
  z-index: 2; 
} 

✅ .box2가 .box1보다 위에 표시된다.
✅ 숫자가 클수록 위쪽, 작을수록 아래쪽


🧱 2. z-index가 동작하려면 조건이 있다

“position 속성이 있어야 z-index가 작동한다.”

즉, 아래처럼 position이 없는 경우는 의미가 없다 👇

div { 
  z-index: 10; /* 무시됨 */ 
} 

✅ position: relative, absolute, fixed, sticky 중 하나를 반드시 포함해야 한다.


⚙️ 3. 기본 쌓임 순서 (Stacking Order)

브라우저는 요소를 다음 순서로 겹친다 👇

1️⃣ z-index가 없는 요소들 (기본 순서)
2️⃣ z-index가 있는 요소들 (낮은 값 → 높은 값 순)
3️⃣ 새로운 쌓임 맥락이 생성된 요소들


🧩 기본 예시

<div class="red"></div> 
<div class="blue"></div> 
.red { 
  width: 200px; height: 200px; 
  background: crimson; 
} 
.blue { 
  width: 200px; height: 200px; 
  background: royalblue; 
  margin-left: -100px; 
} 

✅ HTML 상에서 나중에 적힌 .blue가 .red 위에 겹친다.
나중에 작성된 요소가 위에 쌓이는 것이 기본 규칙


🧱 4. z-index가 숫자로 비교될 때의 기준

.red { 
  position: relative; 
  z-index: 10; 
} 
.blue { 
  position: relative; 
  z-index: 5; 
} 

✅ .red가 .blue 위로 올라간다.
💡 단, 두 요소가 같은 쌓임 맥락 안에 있을 때만 유효하다.


🎯 5. 쌓임 맥락(Stacking Context)이란?

“요소가 자기만의 독립된 z-index 세계를 갖는 것”

쌓임 맥락은 레이어 그룹과 비슷하다.
각 그룹(맥락) 안에서만 z-index가 비교되고,
다른 맥락끼리는 서로 간섭할 수 없다.


📦 쌓임 맥락을 만드는 주요 조건

조건 예시

position + z-index 지정 position: relative; z-index: 1;
opacity < 1 opacity: 0.9;
transform 사용 transform: scale(1);
filter, perspective, will-change 등 filter: blur(0);
isolation: isolate; 명시적으로 새 맥락 생성

✅ 즉, transform, opacity, z-index 등만 써도
새로운 쌓임 맥락이 만들어진다.


🧩 예시로 보는 쌓임 맥락

<div class="parent"> 
  <div class="child"></div> 
</div> 
<div class="box"></div> 
.parent { 
  position: relative; 
  z-index: 1; 
} 
.child { 
  position: absolute; 
  z-index: 9999; 
  width: 100px; height: 100px; background: orange; 
} 
.box { 
  position: relative; 
  z-index: 2; 
  width: 200px; height: 200px; background: skyblue; 
  margin-top: -80px; 
} 

✅ .child의 z-index가 9999여도 .box 아래에 가려진다.

왜냐하면 .child는 .parent의 “쌓임 맥락” 안에 있기 때문.
즉, .parent 밖으로는 영향력이 없다.

💬 “쌓임 맥락은 다른 맥락의 z-index보다 독립적이다.”


⚙️ 6. z-index가 안 먹는 대표적인 상황

상황 원인 해결법

z-index가 안 먹는다 position이 없음 position: relative 추가
9999 줬는데도 아래에 깔림 다른 쌓임 맥락 안에 있음 부모의 z-index 조정
sticky 요소가 덮임 다른 fixed / transform 맥락 존재 transform 제거 또는 z-index 재조정
opacity가 있는 부모 자동으로 쌓임 맥락 생성 부모에 z-index 명시적으로 지정

🧩 7. z-index와 transform의 관계

.card { 
  transform: translateY(0); /* 단 0이라도 transform이 있으면 새로운 맥락 생성 */ 
} 

💡 transform이 선언된 순간, 해당 요소는 자기만의 z-index 세계를 만든다.
그래서 그 아래 자식들의 z-index는 부모 밖의 요소와 비교되지 않는다.


🧮 8. 실제 프로젝트에서 자주 발생하는 문제

① 모달창이 헤더 아래로 깔릴 때

.header { 
  position: fixed; 
  z-index: 1000; 
} 
.modal { 
  position: fixed; 
  z-index: 9999; 
} 

✅ 해결:
모달을 <body>의 가장 아래쪽에 렌더링
혹은 transform이 걸린 부모 요소 바깥에 위치시키기.


② 드롭다운 메뉴가 가려질 때

.dropdown { 
  position: relative; 
  z-index: 10; 
} 
.header { 
  transform: translateZ(0); /* 무심코 추가한 transform */ 
} 

✅ 해결:
transform을 없애거나 header에 z-index를 낮게 명시.


③ 슬라이더 / 팝업 등 겹침 요소 관리

💡 추천 패턴:

:root { 
  --z-header: 100; 
  --z-modal: 1000; 
  --z-tooltip: 1100; 
  --z-toast: 1200; 
} 

✅ 미리 z-index 계층을 변수로 정리해두면 유지보수 매우 쉬워진다.


🎨 9. 실전 예제 — 모달 + 툴팁 겹침 정리

<header>Header</header> 
<main> 
  <button id="showModal">모달 열기</button> 
</main> 
<div class="modal">모달창</div> 
<div class="tooltip">툴팁</div> 
header { 
  position: fixed; 
  top: 0; 
  left: 0; 
  right: 0; 
  background: royalblue; 
  z-index: 100; 
  padding: 10px; 
  color: white; 
} 
 
.modal { 
  position: fixed; 
  inset: 0; 
  background: rgba(0,0,0,0.4); 
  display: flex; 
  justify-content: center; 
  align-items: center; 
  z-index: 1000; 
} 
 
.tooltip { 
  position: absolute; 
  top: 60px; 
  left: 20px; 
  background: #333; 
  color: white; 
  padding: 8px 12px; 
  border-radius: 6px; 
  z-index: 1100; 
} 

✅ 계층 구조:
header(100) < modal(1000) < tooltip(1100)


⚡ 10. z-index 관리 꿀팁 요약

상황 추천 값 설명

기본 콘텐츠 1~10 일반 섹션
고정 헤더/푸터 100~200 상단/하단 고정
모달 / 오버레이 1000 이상 최상단 배치
툴팁 / 드롭다운 1100~1200 모달 위
알림 / 토스트 1300 이상 가장 위

💬 규칙적인 숫자 체계를 갖추면 충돌 없이 정리 가능하다.


🏁 11. 마무리 — “z-index는 숫자 싸움이 아니라 맥락 싸움이다”

z-index는 단순히 “큰 숫자를 주면 위로 간다”가 아니다.
요소가 어느 “쌓임 맥락” 안에 속하느냐가 더 중요하다.

💬 “9999보다 강한 건, 더 높은 맥락이다.”

이제 다음 편에서는
12. CSS Transform과 Transition 고급 활용 — 3D 회전, 회전축, 스케일 애니메이션
을 통해 시각적 역동성을 한 단계 더 높여보자.