이 글은 https://coder-coder.com/z-index-isnt-working/의
번역글입니다. 오타 및 오역 제보 기쁘게 받도록 하겠습니다.
z-index는 요소들을 다른 레이어 위에 겹칠수 있게하는 css 속성입니다. 처음에는 보면 간단해보이지만 정말로 간단합니다.
z-index를 999999로 설정해도 원하는 데로 동작하지 않을 수 있는 비직관적인 이상한 규칙이 있습니다!
이 기사에서는 z-index가 작동하지않는 가장 흔한 이유 4가지와 해결 방법을 설명할 것입니다.
1. 같은 쌓임 맥락(stacking context)의 요소들은 이전 요소들 위에 있는 요소들과 함께 순서대로 표시됩니다.
첫 번째 예제에서는 3가지 메인 요소들을 포함하는 상대적으로 간단한 레이아웃이 있습니다.
- 고양이의 이미지
- 텍스트가 있는 흰색 블록
- 같은 고양이의 다른 이미지
위의 내용들에 대한 HTML 마크업입니다.
<div class="cat-top"></div>
<div class="content__block">
Meow meow meow...
</div>
<div class="cat-bottom"></div>
이 레이아웃에서 흰색 텍스트 블록이 두 고양이의 상단에 있는 것이 이상적입니다.
이를 위해 두 고양이 이미지의 css에 음수 margins을 추가하여 흰색 블록이 겹치도록 했습니다.
.cat-top {
margin-bottom: -110px;
}.cat-bottom {
float: right;
margin-top: -120px;
}
첫번째 고양이는 원하는데로 흰색 텍스트 블록 아래에 있지만, 두번째 고양이 이미지는 블록의 위에 있습니다!
왜 이런 일이 일어났을까요?
그 이유는 웹 페이지의 natural stacking order 때문입니다. 이 규착은 기본적으로 어떤 요소가 맨 위에 있거나 맨 아래에 있을지를 결정합니다.
요소들에 z-index가 설정되지 않아도 stacking order에 의해 요소들의 위치가 결정됩니다.
위의 예제의 경우 요소들에 z-index 값이 none입니다. 그래서 stacking order는 외관의 순서에 따라 결정됩니다. 규칙에 의하면 마크업에서 나중에 오는 요소는 앞에 오는 요소의 위에 있습니다.
(Mozilla 개발자 네트워크에서 더 많은 stacking order에 대해서 읽을 수 있습니다. link)
위의 예제에서는 stacking order 규칙을 따르고 있습니다. 그래서 첫번째 고양이는 흰색 블록 요소 아래에 있고 흰색 블록은 두번째 고양이 밑에 있습니다.
좋아, stacking order는 알았습니다. 그러면 두번째 고양이가 흰색 블록 밑에 있도록 css를 고치는 방법은 무엇입니까?
이제 두 번째 이유를 보러가 봅시다.
2. Element의 위치가 설정되지 않았습니다.
stacking order가 결정되기위한 다른 가이드라인 중 하나는 element에 position이 설정되었는지 아닌지에 의해 결정됩니다.
element의 위치를 설정하려면 static이 아닌 relative, absolute와같은 값을 CSS의 position 속성을 추가해주세요.
이 규칙에 따르면 배치된 요소들은 배치되지않은 요소들의 위에 표시됩니다.
그래서 흰색 블록에 position: relative를 설정하고 두 고양이 요소들의 position을 설정하지 않으면 고양이의 위에 흰색 블록이 놓여집니다.
그러면 아래의 이미지처럼 보여집니다.
woohoo!
지금, 다음으로 원하는 것은 아랫쪽의 고양이를 transform 속성을 사용하여 거꾸로 돌리는 것입니다. 그러면 두 고양이가 흰색 블록 아래에서 머리만 튀어나올 것입니다.
하지만 z-index와 관련된 더 많은 혼동을 초래할 수 있다. 다음 파트에서는 문제와 해결책을 다룰 것입니다.
3. opacity 또는 transform같은 css 속성들을 설정하면 element가 새로운 stacking context에 배치됩니다.
방금 언급했듯이 우리는 아랫쪽의 고양이를 거꾸로 돌리려고 합니다. 이를 위해 transform: rotate(180deg)를 추가합니다.
.cat-bottom {
float: right;
margin-top: -120px;
transform: rotate(180deg);
}
그런데 하단의 고양이는 다시 흰색 블록의 위에 표시되어버렸습니다!
무슨 일이 일어난 걸까요?
자주 발생하는 이슈는 아닐 수 있지만 stacking order의 다른 측면은 transform 또는 opacity 같은 일부 css 속성들이 element 자체의 새로운 stacking context에 넣는다는 것입니다.
그렇다는 것은 .cat-bottom에 transform을 추가하면 z-index가 0인 것처럼 동작한다는 것을 의미합니다. position 또는 z-index가 설정되어 있지 않아도 말입니다.
(W3.org는 opacity 속성과 어떻게 작동하는지에 대한 문서를 볼 수 있습니다.)
우리는 흰색 블록에 z-index 값을 추가하지 않았고 오직 position: relative만 추가했습니다. 이 방법은 position을 주지않은 고양이 위에 흰색 블록을 배치하기 충분했습니다.
그러나 .bottom-cat element는 z-index: 0에 의해 상대적으로 배치된 것처럼 작동하므로 transform을 주면 흰색 블록 위에 배치됩니다.
이에 대한 해결책은 최소한 흰색 블록에 position: relative를 설정하고 z-index를 명시적으로 설정하는 것입니다. 한 단계 더 나아가서 고양이 요소들에 position: relative와 흰색블록보다 낮은 z-index를 주면 더욱 안전합니다.
.content__block {
position: relative;
z-index: 2;
}
.cat-top, .cat-bottom {
position: relative;
z-index: 1;
}
내 의견으로는 더 기본적인 z-index 이슈들이 모두 해결되지는 않지만 대부분은 해결될것입니다.
이제 z-index가 동작하지않는 마지막 이유를 보러 가봅시다. 마지막 것은 부모와 자식 요소를 포함하기 때문에 더욱 복잡합니다.
4. 부모의 z-index 레벨 때문에 element가 더 낮은 stacking context 안에 있습니다.
아래 예제 코드를 확인해보세요.
위 코드에는 일부 콘텐츠가 포함된 간단한 웹페이지와 콘텐츠 상단에 ‘Send Feedback’이라는 분홍색 탭이 있습니다.
그리고 고양이 사진을 클릭하면 투명한 회색 배경을 가진 모달 창이 열립니다.
그런데 모달 창이 열려있어도 사이드 탭은 여전히 회색 배경 위에 있습니다. 이제 우리가 할 것은 사이드 탭을 포함해서 모든 요소 위에 회색 배경이 표시되게 할 것입니다.
문제가 되는 element의 css를 보러 가봅시다.
.content {
position: relative;
z-index: 1;
}.modal {
position: fixed;
z-index: 100;
}.side-tab {
position: fixed;
z-index: 5;
}
모든 요소들에는 position이 설정되어 있으며 side-tab에는 z-index가 5이며 z-index: 1인 content element의 위에 배치됩니다.
그런 다음 모달은 z-index: 100이므로 side-tab 위에 배치되어야 하지만 모달의 오버레이는 z-index: 5인 side-tab의 밑에 있습니다.
왜 그럴까요??
이전에는 element에 position이 설정되있는지 markup의 순서가 잘 배치되어있는지와 같은 것으로 stacking context에 들어가는 몇가지 요소를 해결했습니다.
하지만 stacking context의 또 다른면에는 자식 요소가 부모의 stacking context로 제한된다는 것입니다.
문제의 3 가지 요소들을 살펴보겠습니다.
<section class="content">
<div class="modal"></div>
</section><div class="side-tab"></div>
마크업을 보면 content와 side tab 요소들이 같은 위계에 있음을 알 수 있습니다. 즉, 마크업에서 같은 레벨에 존재합니다. (z-index 레벨과는 다릅니다.) 그리고 모달은 content의 자식 요소입니다.
모달이 content 요소 안에 있기 때문에 z-index: 100 은 content 요소 안에서만 효과가 있습니다. 예를 들어 모달과 같은 위계의 다른 자식 요소들이 있다면 그 요소들끼리는 z-index값에 따라서 위 또는 아래에 배치됩니다.
그러나 부모 content 요소의 z-index가 1로 설정되어 있으므로 자식 요소들의 z-index값은 부모 요소밖의 요소들에는 아무 의미가 없습니다.
모달을 포함한 자식 요소들은 부모의 z-index를 벗어날 수 없습니다.
(이런 식으로 기억할 수 있습니다. 자녀는 부모에의해 강제되며 부모를 벗어날 수 없습니다.)
이 문제에 대한 몇 가지 해결책이 있습니다.
해결책: 모달을 content 부모의 밖. 페이지의 메인 stacking context로 옮깁니다.
수정된 마크업은 다음과 같습니다.
<section class="content"></section><div class="modal"></div><div class="side-tab"></div>
이제 모달 요소는 다른 두 요소들과 같은 위계에 놓여있습니다. 이렇게하면 세 요소가 모두 같은 stacking context에 배치되므로 z-index 레벨이 서로에게 영향을 줄 수 있을것입니다.
이 새로운 stacking context에서 요소들은 위에서 아래로 다음같은 순서대로 쵸시됩니다.
- modal (z-index: 100)
- side tab (z-index: 5)
- content (z-index: 1)
다른 해결책: content에서 position을 제거하여 modal의 z-index를 제한하지 않게합니다.
마크업을 원하지 않거나 변경할 수 없는 경우 content 요소에서 position 설정을 제거하여 이 문제를 해결할 수 있습니다.
.content {
// No position set
}.modal {
position: absolute;
z-index: 100;
}.side-tab {
position: absolute;
z-index: 5;
}
content 요소의 position이 없으니 더 이상 modal에는 z-index의 값에 제한이 없습니다. 따라서 modal을 열면 z-index가 100으로 더 높기때문에 side tab 요소의 위에 모달이 배치됩니다.
이 방법도 해결책이 될 수 있지만 개인적으로는 첫번째 해결책을 권장합니다.
앞으로 어떤 이유에서든지 content 요소를 배치해야하는 경우 stacking context에서 modal의 순서를 다시 제한합니다.
결론
이 튜토리얼이 도움이 되었기를 바랍니다! 요약하면 z-index의 대부분의 이슈들은 두 가지 가이드라인을 따라 해결할 수 있습니다.
- 요소의 위치 및 z-index의 순서가 올바른지 확인하십시오.
- 자녀의 z-index 수준을 제한하는 부모 요소가 없어야합니다.
참고