Menu

CSS z-index: 쌓임 순서와 쌓임 맥락

z-index는 겹친 요소 중 어느 것을 위에 그릴지 정해요. 어떤 요소에서 동작하는지, 쌓임 맥락이 요소를 묶어서 z-index 9999도 질 수 있는 이유, 쌓임 맥락을 만드는 것, 동작하지 않는 z-index를 고치는 법을 알아봐요.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

z-index가 하는 일

요소가 겹치면 z-index가 어느 것을 앞에 그릴지 정해요. 숫자가 높은 쪽이 이겨요. 위치 지정 요소(static이 아닌 모든 position)와 flex, grid 항목에서 동작해요.

z-index가 없으면 HTML에서 나중에 나오는 요소가 앞의 요소 위에 그려져서 C가 B를, B가 A를 덮어요. z-index 값이 이를 뒤집어요. A가 맨 앞, 그다음 C, 그다음 B예요.

값

값뜻
auto (기본값)형제들과 함께 레벨 0에 쌓이고, 쌓임 맥락을 만들지 않아요
0레벨 0이지만 쌓임 맥락을 만들어요
양의 정수더 낮은 값 앞에 놓여요
음의 정수레벨 0 뒤에, 부모가 쌓임 맥락을 만든다면 부모 콘텐츠 뒤에 놓여요

정수만 유효해요. z-index: 1.5는 무시돼요.

z-index 9999가 질 수 있는 이유: 쌓임 맥락

z-index 값은 페이지 전체에서 비교되지 않아요. 요소들은 쌓임 맥락으로 묶이고, z-index는 같은 맥락 안의 요소들끼리만 순서를 정해요. 맥락 자체는 그 맥락을 만든 요소의 z-index로 하나의 레이어로 배치돼요.

아래에서 파란 드롭다운은 z-index: 9999지만 z-index: 1인 헤더 안에 있어요. 그 헤더의 형제인 초록 배너는 z-index: 2예요. 드롭다운을 포함한 헤더 레이어 전체가 배너 아래에 있어요.

버튼을 눌러 보세요. z-index: auto가 되면 헤더가 더 이상 쌓임 맥락을 만들지 않아서, 드롭다운의 9999가 배너의 2와 직접 비교되고 드롭다운이 앞으로 나와요. 드롭다운을 99999로 올렸어도 아무 소용이 없었을 거예요.

쌓임 맥락을 만드는 것

다음 중 하나라도 해당하면 요소가 자기만의 쌓임 맥락이 되어 안에 있는 모든 것의 z-index를 가둬요.

속성조건
position: relative 또는 absoluteauto가 아닌 z-index와 함께
position: fixed 또는 sticky항상
flex나 grid 항목auto가 아닌 z-index와 함께
opacity1 미만
transform, scale, rotate, translatenone이 아닌 모든 값
filter, backdrop-filternone이 아닌 모든 값
isolationisolate
mix-blend-modenormal이 아닌 모든 값
will-change위 속성 중 하나를 지정할 때
containlayout이나 paint(그리고 strict, content)

뜻밖인 것은 opacity와 transform이에요. 부모에 페이드나 hover 애니메이션을 추가했더니 갑자기 드롭다운이 다음 섹션 뒤로 들어가는 일이 생겨요.

툴팁의 z-index: 10이면 다음 열 위에 놓여야 해요. 그런데 opacity: 0.99가 첫 번째 열을 z-index auto(레벨 0)인 쌓임 맥락으로 만들고, 두 번째 열은 같은 레벨에서 HTML상 나중에 나오기 때문에 툴팁을 포함한 첫 번째 열 전체 위에 그려져요. opacity 줄을 지우면 툴팁이 다시 앞으로 나와요.

음수 z-index

음수 z-index는 요소를 형제들 뒤로 보내요. 부모가 쌓임 맥락을 만들지 않으면 부모의 배경 뒤로까지 갈 수 있어서 자주 당황하게 돼요. 부모에 isolation: isolate를 주면 다른 시각적 효과 없이 맥락을 만들어서 음수 자식을 그 안에 붙잡아 둬요.

isolation이 없으면 주황색 틀이 버튼 자체의 회색 배경 뒤로 떨어져서 가장자리만 보여요. isolation: isolate가 있으면 틀이 버튼의 쌓임 맥락 안에 머물러요. 배경 위, 텍스트 아래예요.

z-index 단계

숫자를 계속 올리지 말고 사이트 전체에 쓸 이름 붙은 레이어 몇 개를 정하세요.

:root {
  --z-dropdown: 10;
  --z-sticky: 20;
  --z-overlay: 30;
  --z-modal: 40;
  --z-toast: 50;
}
.modal { position: fixed; z-index: var(--z-modal); }

대부분의 레이어 버그는 숫자 버그가 아니라 쌓임 맥락 버그예요. 그래서 작은 단계와, 안에서 z-index를 쓰는 컴포넌트에 isolation: isolate를 주는 것만으로 많이 해결돼요. z-index가 동작하려면 위치 지정이 필요하고, 이는 position 페이지에서 다뤄요.

자주 하는 실수

  • static 요소에 z-index. position: relative를 추가하세요(또는 flex나 grid 항목으로 만드세요).
  • 9999까지 올리기. 부모가 경쟁 요소보다 아래에 있는 쌓임 맥락을 만들면 어떤 자식 값도 이길 수 없어요. 대신 그 맥락을 찾으세요.
  • 부모에 새로 넣은 opacity, transform, filter. 갑자기 드롭다운을 가둘 수 있어요.
  • 소수 값. z-index: 1.5는 잘못된 값이에요.
  • z-index: 0과 auto가 같게 동작할 거라고 기대하기. 0은 쌓임 맥락을 만들고, auto는 만들지 않아요.
  • 깊이 중첩된 컴포넌트 안의 모달. <body> 끝 가까이에 렌더링하거나(또는 <dialog> 요소의 top layer를 쓰거나) 해서 어떤 조상 맥락도 가두지 못하게 하세요.

자주 묻는 질문

z-index는 무엇을 하나요?

겹친 요소의 쌓임 순서를 정해요. 같은 쌓임 맥락 안에서 값이 높은 쪽이 낮은 쪽 앞에 그려져요. 기본값은 auto이고, 값은 음수를 포함한 정수예요.

z-index가 동작하지 않는 이유는 무엇인가요?

요소에 위치가 지정되지 않았거나(z-index는 static이 아닌 position, 또는 flex나 grid 자식이어야 해요), 순서가 더 낮은 쌓임 맥락을 만드는 부모 안에 있기 때문이에요. 자식은 자기 z-index와 상관없이, 자기 쌓임 맥락보다 위에 놓인 요소를 넘어설 수 없어요.

쌓임 맥락(stacking context)이란 무엇인가요?

하나의 레이어로 함께 쌓이는 요소 묶음이에요. 안에서는 자식들이 z-index로 정렬되고, 밖에서는 그 맥락을 만든 요소의 z-index로 묶음 전체가 배치돼요.

무엇이 쌓임 맥락을 만드나요?

여러 가지가 있어요. 루트 요소, auto가 아닌 z-index를 가진 위치 지정 요소, position: fixed나 sticky, z-index가 있는 flex나 grid 자식, 1 미만의 opacity, transform, filter, isolation: isolate, 그리고 이 속성들에 대한 will-change예요.

z-index는 position 없이도 동작하나요?

일반 block이나 inline 요소에서는 안 돼요. position: static은 무시해요. flex 항목과 grid 항목에서는 position 없이도 동작해요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기