본문 바로가기

개발자 강화/프론트엔드

[매일메일+개발] 쌓임 맥락 + 실무 경험담

크아악 겪어보지 않으면 모르는 쌓임 맥락

(겪어보고 뒤통수가 얼얼해서 정리한다는 뜻)


화면 중앙에 표시되는 요소를 만들고 나서, 좌측에 있는 요소를 만들었다

대략 아래와 같은 상황

 

중앙 요소는 항상 가운데 위치하지만, 평소에 노출되지 않을 땐 투명하다.

따라서, 배치 상으로는 좌측 요소와 겹치더라도 ui 상으로는 문제가 없다

 

근데 좌측에 있는 요소가 클릭이 안되길래 확인해보니,

저 그림에서 겹치는 영역을 클릭했을 때 좌측 요소의 클릭이 안먹히고 있었다

어라?!

 

이상한 점...

중앙 요소의 z-index는 10, 좌측 요소는 100으로 훨씬 높았다

좌측 요소(z-100)가 더 위에 렌더링 될 것이라고 생각했지만, 실제로는 중앙 요소(z-10)가 클릭을 가로채고 있었음

 

그것은 Stacking Context (쌓임 맥락) 때문!


Stacking Context란?

 

HTML 요소들이 가상의 z축을 따라 3차원 공간에서 쌓이는 개념

각 Stacking Context가 독립적인 3D 공간을 형성하며, z-index 비교는 같은 맥락 내에서만 이뤄짐

 

새로운 Stacking Context를 생성하는 조건

- position 속성이 relative 또는 absolute이고 z-index 값이 auto가 아닌 경우

- position 속성이 fixed 또는 sticky인 경우 (z-index 없어도 새로운 context 생성)

- display가 flex 또는 grid이고, z-index가 설정된 경우

- opacity 값이 1 미만인 경우

- transform, filter 등의 속성

 

이 상황에서 실제 렌더링 순서

 

<body> (root stacking context)
  ㄴ 좌측 요소 (z-index: 100, position: relative)
  ㄴ 중앙 요소 (position: fixed) <- 새로운 stacking context 생성

 

 

1. 중앙 요소(z-10): 루트 레벨에서 별도의 독립적인 3D 공간을 형성

2. 좌측 요소(z-100): z-index 값 100은 자신의 context 내에서만 유효함

3. 루트 레벨에서는 DOM 순서(또는 position 타입)에 따라 렌더링 순서 결정

4. 따라서, fixed 요소가 나중에 렌더링되어 표시됨

 

중앙 요소가 투명하거나, 내용이 없어도 기본적으로 pointer-events: auto 상태이므로,

해당 영역에 발생하는 모든 클릭 이벤트를 가로채고 있었음

 

흠, 근데 왜 fixed를 썼을까?

만약 저 중앙 요소도 클릭이 필요하고, 좌측 요소도 클릭이 필요하면

stacking context를 고려하며 전반적으로 구조를 조정했을 것이다

 

하지만, 이전 개발자가 fixed를 사용한 이유도 고려해야 한다

fixed는 뷰포트(화면) 기준으로 위치를 고정하는 속성으로,

일관적으로 화면 정중앙에 요소를 배치하기 위해 사용했을 것이다

 

여러 레이어가 중첩된 구조에서는 부모 요소를 기준으로 absolute를 사용해

의도한 위치에 배치하기 어려웠을 것이다

 

해결 방법

- 중앙 요소에 pointer-events-none을 추가함

- 클릭 이벤트를 무시하도록 설정하면, 하위 요소로 클릭 이벤트를 전파시킬 수 있음

 

중앙 요소는 특정 상황에서 트리거되어 화면에 잠시 노출됐다 사라지며,

클릭 함수로 액션 트리거가 필요하지 않은 단순 ui 요소였다

그래서 클릭을 투과시켜 좌측 영역에 이벤트를 전파하는 것만으로도 충분했다

 

최소 수정으로 혹시 모를 side effect를 방지하면서, 빠른 시간 내에 문제를 해결하기 위해 이와 같은 선택을 했다

 

교훈

- position 속성(특히 fixed/sticky)이 새로운 Stacking Context를 생성함을 항상 고려해야 함

- 단순히 z-index 숫자만 보고 판단하면 안됨

- chrome dev tools의 layers 탭에서 stacking context 확인


 

이 사건을 겪고 뒤통수의 얼얼함이 가시기도 전에

'매일메일'로 쌓임 맥락에 대한 리포트를 받았다 

(믿고 있었다구~!)


 

'매일메일' 내용 정리

 

쌓임 맥락(Stacking Context)

- 가상의 축을 상정해 HTML 요소들을 3차원으로 개념화함

- 요소들이 쌓이는 순서에 영향을 미침

 

일반적인 개념

- 기본적으로 HTML 요소는 DOM 순서에 따라 쌓임

- HTML 상에서 위쪽에 위치할수록 아래쪽에 쌓임

 

- position 속성이 적용되어 있는 요소들은 

- z-index 값이 낮을수록 아래쪽으로, 높을수록 위쪽으로 쌓임

 

특수한 경우

- 특정 조건이 충족되면 새로운 쌓임 맥락이 생성됨 (위 챕터에서 설명한 조건)

- 독립적인 3차원 공간을 만들고, 부모의 쌓임 맥락의 영향을 받지 않음

- 해당 쌓임 맥락 내에서만 비교가 이뤄져 쌓임 순서가 결정됨

 

예시

<div style="position: relative; z-index: 1;">
    A 요소 (z-index: 1)
    <div style="position: absolute; z-index: 999;">
        A-1 요소 (z-index: 999)
    </div>
</div>

<div style="position: relative; z-index: 2;">
    B 요소 (z-index: 2)
</div>

 

가장 위쪽에 쌓이는 요소는 B 요소

그 다음 A-1 요소, A 요소 순으로 쌓임

 

최상의 쌓임 맥락 내 요소들인 A 요소와 B 요소의 z-index 값을 비교함

B 요소가 크기 때문에 가장 위쪽에 쌓임

 

A 요소가 형성한 쌓임 맥락 내에서 z-index 값을 비교함

A 요소보다 z-index가 큰 A-1 요소가 더 위쪽에 쌓임

 

z-index 값이 더 크다고 무조건 위쪽에 쌓이는 건 아님

 


 

아무튼 여러분들도 뒤통수가 얼얼하지 않게 조심하십시오

z-index는 만능이 아니니까 맥락 파악 없이 무작정 쌓아 올리지 마십시오

(레거시에 z-100, z-1000이런거 볼 때마다 어지러움...ㅠㅠ)

 

아무튼 화이팅

 

이 사건 발생일: 25.10.02

이 글을 작성한 날: 25.11.29

글 좀 자주 써야겠다


출처

1. 매일메일251129 쌓임 맥락에 대해 설명해주세요 https://www.maeil-mail.kr/question/158

2. 뒤통수가 얼얼한 쌓임 맥락 경험

3. 킹 갓 수빈님의 조언 ('z-index 무관하게 absolute 엘리먼트 렌더링 위치에 따라 레이아웃 쌓임이 역전될 수 있다')

728x90