z-index & stacking context

GI JUNG·2024년 3월 26일
0

css

목록 보기
3/3
post-thumbnail

⚙️ Browser Stacking element

z-index, stacking context를 정확히 이해하기 위해서는 기본적으로 브라우저가 어떤 기준으로 요소들을 쌓아 시각적으로 먼저 노출하는지 알아야 한다.

브라우저는 기본적으로 html구조 순서대로 element들을 쌓아 시각적으로 어떤 것이 먼저 보일 지 쌓임의 순서를 결정한다.

하지만, 기본적인 쌓임 순서를 두 가지 속성을 이용하여 순서를 조작할 수 있다.

  • z-index
  • position

<body>
  <div class="overlap">
    <div class="box1">1</div>
    <div class="box2">2</div>
    <div class="box3">3</div>
  </div>
</body>
body {
  width: 100vw;
  height: 100vh;
}

.overlap {
  display: grid;
  grid: 1 / 1;
  width: 400px;
}

.overlap div {
  grid-row-start: 1;
  grid-column-start: 1;
  width: 200px;
  height: 200px;
}

.box1 {
  background-color: red;
  transform: translateX(50px);
}

.box2 {
  background-color: orange;
  transform: translateX(100px);
}

.box3 {
  background-color: green;
  transform: translateX(150px);
}

3개의 박스의 높이와 넓이가 200px이지만 브라우저의 기본 쌓임 순서대로 쌓여 맨 마지막에 선언한 div.box3가 가장 상위로 노출된다.

1️⃣ Position

브라우저에서 position을 적용하여 쌓임순서를 조작할 수 있다.
하지만, 어떤 기준을 근거로 쌓이는지를 알아야 하는데 그 기준이 아래 그림과 같다.

  • inline element가 block element보다 상위에 쌓인다.
  • positioned(static을 제외한 값) > floated > non-position(position: static) 순으로 상위에 쌓인다.

상위에 노출 시키고자 무작정 position: relative를 사용했지만, 다른 stacking context라면 다르게 동작한다.

2️⃣ z-index

z-index는 요소가 overlap(겹침)됐을 때, z-axis(z축)를 기준으로 z-order를 결정하여 Screen상에 시각적으로 어떤 요소를 먼저 노출시킬시 결정하는 css 속성이다. 이 때 중요한 것은 z-indexstacking context내에서 결정되고 유효하며 stacking context내의 요소들은 벗어날 수 없는 경계가 존재한다.

좀 더 쉽게 풀어서 설명하자면, 하위 stacking context내에 있는 요소의 z-index가 아무리 크더라도 z-index가 더 작은 상위 stacking context에 있는 요소가 시각적으로 먼저 노출된다.(아래 그림 참고)

  • 노란색 👉🏻 root stacking context
  • 연두색 & 파란색 👉🏻 Stacking context
  • 빨간색 👉🏻 연두색 stacking context에 존재하는 요소
  • 보라색 👉🏻 파란색 stacking context에 존재하는 요소

💡 z-index는 positioned element(position: static ❌) 요소에만 동작한다.

<z-index와 position 쌓임 순서>

그럼 stacking context가 어떤 것이고 언제 생성이 되는지 알아보자

🔎 Stacking Context

stacking context는 공통 부모요소를 가지는 자식 요소들의 그룹이다.
위에서 언급했 듯이 동일한 stacking context내에서 z-index가 특정되며 유효하다고 했다.

결국 z-index의 동작원리를 이해하는 가장 키 포인트는 같은 stacking context를 공유하는지에 대한 유무에 있다. 따라서 Stacking context가 어느 상황에 생성되는지를 알아야 한다.

stacking context가 생성되는 경우는 매우 많지만 자주 쓰는 것으로 추려보면 아래와 같다.

  • position -> positioned가 된 element가 stacking context생성
    • z-index의 auto가 아님과 동시 에 relative, absolute
    • sticky, fixed
  • flex, grid container내의 자식요소가 z-index가 auto가 아닐 때 -> z-index를 준 자식은 새로운 stacking context를 생성
  • opacity, transform, filter, backdrop-filter, clip-path, perspective, will-change가 기본 값이 아닐 때 -> 해당 속성을 준 element가 stacking context 생성

이제 다시 위의 overlap의 코드를 보면 transform이 적용되었으므로 각각의 box들은 각기 다른 stacking context에 생성된다.

이제 z-index는 stacking context에 제약된다는 사실을 증명하기 위해 모든 box의 자식으로 span을 추가하고 box1의 자식에 큰 z-index를 주자.

<body>
	<div class="overlap">
	  <div class="box1">
	    <span>1</span>
	  </div>
	  <div class="box2">
	    <span>2</span>
	  </div>
	  <div class="box3">
	    <span>3</span>
	  </div>
	</div>
</body>
.box1 > span {
  width: 100px;
  height: 100px;
  background-color: white;
  z-index: 100;
}

z-index를 100이나 주었는데 box3보다 아래에 깔려있다. 이렇게 요소가 겹치게 되면 무작정 z-index를 준다고 상위로 노출되지 않는구나 확인할 수 있다.

이제 box1>span을 노출 시키기 위해서 방법을 찾아보자. 일단, 내가 생각한 것은 2가지 방법이 존재한다.

  1. box로 인해 생성된 stacking context를 지우기 위해 transform을 제거
  2. stacking context자체에 z-index를 주어 z-order를 증가시킴

상황에 따라 다른 전략을 선택하면 되겠지만 난 2번을 선택하여 span만 노출시키면 되는 방향으로 가보겠다.

.box1 {
	...//
	z-index: 1;
}

<위 코드 내 요소들의 쌓임 순서 시각화>

이렇게 stacking context 자체의 z-order를 조절하여 문제를 해결할 수 있다.
하지만, 이런 상황에서 box1>span은 box1이 생성한 stacking context에 있기 때문에 box1자체도 상위로 노출됨은 필연적이다.
만약에 box1말고 span만 노출시키고 싶다면 1번의 전략을 선택하면 해결할 수 있다.

stack overflow에서 같은 문제에 대한 해결책으로도 z-index가 원하는 대로 동작하기 위해서는 같은 stacking context를 공유해야한다고 한다.

🔥 마치며

이것저것 실험해보면서 추가로 정리한 것을 정리해보자.

  1. stacking context를 공유한다고 가정하면 stacking context가 생성되면 다른 자식 요소보다 z-order가 높아진다.
  2. 이해를 돕기 위해 stacking context를 공통 부모요소를 가지는 자식 요소들의 그룹이라고 어렵게 생각하면 초점이 자식들의 그룹으로 생각하여 요소들의 z-order를 추적하기 어렵지만 stacking context를 촉발시키는 그 요소 자체(공통 부모)를 다른 layer 즉, stacking context라 생각하면 z-order를 추적하기 쉽다.
  3. stacking context가 그룹과 같은 추상적인 요소인 것 같지만 2번의 이유로 z-index 또한 줄 수 있다.

input type range가 가지고 있는 기본적인 브라우저 스타일을 제거하면서 dual range slider를 구현하다가 z-index가 원하는대로 작동하지 않아 찾다보니 stacking context의 존재를 알고 문제를 해결할 수 있었다.
또한 flex나 grid에서 z-index를 주고 적용되는 것에 아무런 의문을 품지 않았다.
flex나 grid가 적용된 자식들은 사실상 position: static이므로 z-index를 준다고 적용되는것이 아니기 때문이다. 하지만, mdn에서 정의한 위의 조건들을 기반으로 하면 flex container내의 자식 요소에게 z-index를 주면 stacking context가 생성되어 z-order를 적용할 수 있다는 것을 알았다.

📚 참고

position
when does the stacking context created by mdn
z-index & stacking context explanation blog

profile
step by step

0개의 댓글