CSS / z-index / 요소의 수직 위치 정하는 속성

z-index는 요소가 겹칠 때 화면의 앞뒤, 즉 z축에서 어느 쪽에 그려지는지 정하는 CSS 속성입니다. 제목에서 말하는 “수직 위치”는 화면의 위아래 좌표를 바꾸는 뜻이 아니라 겹침의 깊이를 가리킵니다. 같은 쌓임 맥락(stacking context) 안에서는 큰 정수 값이 더 앞에 오지만, 부모가 만든 맥락을 넘어서 자식끼리 숫자를 직접 비교할 수는 없습니다.

적용 대상과 auto·정수 값 구분하기

일반적인 위치 지정 요소에는 relative·absolute·fixed·sticky 같은 position 설정과 함께 z-index를 사용합니다. Flexbox와 Grid의 항목은 position이 static이어도 z-index를 사용할 수 있습니다. 일반 블록 요소에 숫자만 넣었는데 효과가 없다면 적용 대상인지 먼저 확인하세요.

초기값은 auto입니다. 위치 지정 요소에서 auto와 0은 비슷한 앞뒤 위치로 보일 수 있지만, relative·absolute 요소에 정수 z-index를 주면 새 쌓임 맥락이 만들어진다는 차이가 있습니다. 같은 조건에서 값까지 같을 때는 문서 순서가 관여할 수 있으나, 모든 요소가 단순히 HTML에 늦게 쓰였다는 이유만으로 항상 앞에 오는 것은 아닙니다.

전체 예제: 같은 범위와 다른 부모 비교하기

아래 코드를 z-index.html로 저장하고 브라우저에서 엽니다. 각 stage의 isolation: isolate는 두 실험 구역이 서로 간섭하지 않도록 쌓임 맥락을 분리합니다. 파란 상자와 초록 상자가 겹치는 부분에 주목하세요.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>z-index와 부모의 쌓임 맥락</title>
  <style>
    body { margin: 20px; font: 16px/1.6 "Noto Sans KR", sans-serif; color: #203348; }
* { box-sizing: border-box; }
    h1 { font-size: 24px; }
    h2 { font-size: 19px; }
    .stage { position: relative; isolation: isolate; max-width: 500px; height: 180px;
      border: 1px solid #9aafc2; margin-bottom: 24px; }
    .box { position: absolute; width: 150px; height: 100px; padding: 10px; color: white; }
    .simple .a { left: 10px; top: 10px; background: #1768a5; z-index: 1; }
    .simple .b { left: 100px; top: 60px; background: #087b76; z-index: 2; }
    .parent-a { position: absolute; left: 10px; top: 10px; width: 180px; height: 120px;
      background: #dcebf7; z-index: 1; }
    .child { left: 50px; top: 40px; background: #1768a5; z-index: 9999; }
    .parent-b { left: 120px; top: 70px; background: #087b76; z-index: 2; }
  </style>
</head>
<body>
<h1>z-index의 비교 범위</h1>
<h2>같은 쌓임 맥락</h2>
<div class="stage simple">
  <div class="box a">A: 1</div>
  <div class="box b">B: 2</div>
</div>
<h2>부모가 서로 다른 쌓임 맥락</h2>
<div class="stage nested">
  <div class="parent-a">부모 A: 1
    <div class="box child">자식<br>9999</div>
  </div>
  <div class="box parent-b">부모 B: 2</div>
</div>
</body>
</html>

첫 구역은 A의 1과 B의 2를 같은 범위에서 비교하므로 B가 앞에 보입니다. 두 번째는 자식의 값이 9999여도 부모 A가 1인 맥락에 속해 있어 부모 B의 2보다 뒤에 놓입니다. 자식의 숫자를 더 크게 바꾸는 것만으로는 이 관계를 뒤집을 수 없습니다.

같은 맥락의 1·2 상자와 부모 A의 1 안에 있는 자식 9999가 부모 B의 2 뒤에 놓이는 실행 화면

자식 값을 올려도 앞으로 나오지 않는 이유

쌓임 맥락은 안의 요소를 묶어 부모 범위에서 하나의 단위처럼 취급합니다. 따라서 두 번째 구역에서 먼저 비교되는 것은 자식 9999와 부모 B의 2가 아니라 부모 A의 1과 부모 B의 2입니다. 자식의 높은 값은 부모 A 안의 요소들 사이에서 의미가 있습니다.

첫 번째 구역의 .simple .a에 있는 z-index만 3으로 바꾸면 A가 B보다 앞에 옵니다. 원래 1로 되돌린 다음, 이번에는 두 번째 구역의 parent-a 값만 3으로 바꾸세요. 이제 부모 A의 묶음이 앞으로 와서 자식도 B 앞에 나타납니다. 두 값을 동시에 바꾸지 말고 각 비교 후 되돌립니다.

쌓임 맥락은 z-index만으로 생기지 않습니다. transform이 none이 아니거나 opacity가 1보다 작은 조상, isolation: isolate 같은 설정도 영향을 줄 수 있습니다. 개발자 도구에서 가려지는 요소부터 조상 방향으로 확인하고, 비교하려는 두 요소가 어느 맥락에 속하는지 찾는 것이 중요합니다.

음수 값·잘림·상단 레이어 점검하기

음수 z-index도 사용할 수 있지만 요소가 부모나 다른 배경 뒤로 들어가 보이지 않을 수 있습니다. 음수 값으로 장식을 뒤에 두기 전에 배경과 쌓임 범위를 확인하세요. 큰 숫자를 계속 더하는 방식보다 헤더·드롭다운·알림처럼 실제로 비교해야 하는 범위를 정리하는 편이 유지보수에 유리합니다.

메뉴가 부모의 overflow: hidden에 잘리는 것은 겹침 순서와 다른 문제입니다. z-index를 올려도 잘림 영역 밖으로 나오는 해결책이 되지는 않습니다. 또한 모달 dialog나 열린 popover처럼 브라우저의 상단 레이어(top layer)에 배치되는 요소는 일반 문서의 z-index 숫자를 크게 하는 것과 다른 규칙으로 처리됩니다. 모든 문제를 “숫자가 작아서”라고 판단하지 마세요.

적용 값은 MDN의 z-index 설명, 생성 조건과 부모·자식 비교는 쌓임 맥락 안내를 참고할 수 있습니다.