포지셔닝과 z-index


상품 사진의 오른쪽 위 모서리에 작은 "Sale" 배지를 올리고 싶다고 해봅시다. 페이지가 스크롤되어도 헤더는 그 자리에 그대로 있었으면 합니다. 그리고 페이지의 다른 모든 것 위에 떠 있는 대화창도 필요합니다. 일반적인 CSS 여백 조정으로는 이런 걸 할 수 없습니다. 여백은 요소를 그저 순서대로 배치할 뿐이니까요. 포지셔닝은 요소가 그 일반적인 배치 흐름에서 벗어나 여러분이 지정한 정확한 위치에, 심지어 다른 요소 위에도 자리 잡을 수 있게 해주는 도구 모음입니다.
position 속성
모든 요소는 static 포지셔닝 상태로 시작합니다. 쉽게 말해 "페이지 흐름 속 원래 자리에 그대로 있는다"는 뜻입니다. 이게 기본값이고, 대부분의 경우 우리가 원하는 상태이기도 합니다. 포지셔닝이 의미를 갖기 시작하는 시점은 요소를 그 원래 자리에서 벗어나게 하고 싶을 때입니다.
그다음 단계는 position: relative입니다. 이 속성은 top, right, bottom, left라는 네 가지 오프셋 속성을 사용해 요소를 원래 있던 자리에서 살짝 밀어냅니다. 중요한 점은 요소가 원래의 공간을 그대로 유지한다는 것입니다. 다른 요소가 그 빈 공간을 채우러 움직이지 않습니다.
.badge {
position: relative;
top: 10px; /* 원래 자리에서 아래로 10px 밀림 */
left: 20px; /* 원래 자리에서 오른쪽으로 20px 밀림 */
}static 요소에는 top이나 left 오프셋을 줘도 아무 효과가 없습니다. position을 static이 아닌 값으로 지정해야만 이 오프셋들이 작동하기 시작합니다.
static으로 시작하며, 원래 자리에 그대로 있는다는 뜻입니다. position: relative로 바꾸면 top, right, bottom, left로 살짝 밀 수 있고, 원래 공간은 그대로 예약된 채 남습니다. 이 오프셋 속성들은 요소에 position이 지정되어야만 작동하므로, top이 무시되는 것 같다면 먼저 position을 설정했는지 확인하세요. absolute 포지셔닝
position: absolute는 더 큰 변화입니다. 이 속성은 요소를 일반 흐름에서 완전히 빼내므로 더 이상 공간을 차지하지 않고, 주변 요소들은 마치 그 요소가 없었던 것처럼 자리를 좁혀 채웁니다. 그런 다음 같은 top, right, bottom, left 오프셋으로 위치를 지정합니다.
문제는 "무엇을 기준으로 오프셋을 계산하는가"입니다. absolute 요소는 가장 가까운 **포지션이 지정된 조상**을 기준으로 위치를 잡습니다. 즉, 자기만의 position(static이 아닌 값)을 가진 가장 가까운 부모를 기준으로 삼습니다. 그래서 카드 위 배지 패턴은 항상 짝을 이뤄 등장합니다. 카드를 relative로 만들어 기준점으로 삼고, 배지를 absolute로 만들어 카드의 모서리에 자리 잡게 하는 것이죠.
.card {
position: relative; /* 기준점이 됨 */
}
.card .badge {
position: absolute;
top: 8px; /* 카드 위쪽에서 8px */
right: 8px; /* 카드 오른쪽에서 8px */
}카드에 position: relative가 없다면, 배지는 페이지 더 위쪽으로 올라가면서 포지션이 지정된 조상을 찾다가 여러분이 의도하지 않은 곳에 자리 잡게 됩니다.
position: absolute는 요소를 흐름에서 빼내므로 공간을 차지하지 않고 이웃 요소들이 그 자리를 채웁니다. 그런 다음 position이 설정된 가장 가까운 부모를 기준으로 위치가 잡힙니다. 그래서 카드 위 배지 트릭은 짝으로 씁니다. 카드에는 relative, 배지에는 absolute를 줘야 배지가 카드 모서리에 자리 잡지, 엉뚱한 곳에 가지 않습니다. fixed와 sticky
position: fixed는 요소를 화면 자체에 고정합니다. absolute처럼 흐름에서 빠져나오지만, 부모를 기준으로 삼는 대신 눈에 보이는 창인 **뷰포트**를 기준으로 삼습니다. 한번 fixed로 지정되면 페이지를 스크롤해도 화면상 같은 위치에 계속 머뭅니다. 내비게이션 바나 "맨 위로" 버튼이 항상 화면에 보이는 이유가 바로 이것입니다.
.site-header {
position: fixed;
top: 0; /* 창 위쪽에 고정 */
left: 0;
right: 0; /* 전체 너비로 늘어남 */
}position: sticky는 친근한 중간 지점입니다. sticky 요소는 평소에는 페이지와 함께 스크롤되다가, 지정한 기준점에 도달하면 그 위치에 붙어버립니다. 콘텐츠와 함께 위로 스크롤되다가 화면 위쪽에서 멈춰 서는 섹션 제목이 대표적인 예입니다.
.section-title {
position: sticky;
top: 0; /* 위쪽 가장자리에 도달하면 붙음 */
}position: fixed는 요소를 화면에 고정하므로 스크롤해도 그 자리에 그대로 있고, 이 덕분에 헤더나 맨 위로 버튼이 계속 화면에 남습니다. position: sticky는 중간 지점으로, 페이지와 함께 스크롤되다가 top: 0 같은 기준점에 도달하면 붙습니다. fixed는 아래에 있는 콘텐츠와도 겹치므로, 가려질 콘텐츠를 위한 공간을 남겨두세요. z-index로 쌓기
요소들이 겹치면 어느 것을 앞에 둘지 결정해야 합니다. 이를 결정하는 것이 z-index입니다. z-index 값이 클수록 앞쪽에 그려지므로, z-index: 10인 드롭다운이 z-index: 1인 카드를 덮습니다.
모두가 걸려 넘어지는 규칙이 하나 있습니다. z-index는 포지션이 지정된 요소에만 작동합니다. 요소가 아직 static이라면 z-index는 무시됩니다. 그래서 거의 항상 position과 z-index를 함께 설정합니다.
.modal {
position: fixed;
z-index: 100; /* 일반 페이지 콘텐츠 위에 위치 */
}
.modal-overlay {
position: fixed;
z-index: 99; /* 어두운 배경, 모달보다 한 단계 아래 */
}여기서 큰 숫자를 쓸 필요는 거의 없습니다. 1, 10, 100 같은 작고 정돈된 규모가 서로 부딱치는 9999들로 가득한 페이지보다 이해하기 훨씬 쉽습니다.
z-index가 어느 것을 앞에 둘지 결정합니다. 큰 숫자가 이깁니다. 포지션이 지정된 요소에만 작동하므로, 일반 static 요소에 준 z-index는 무시되며, 그래서 position과 z-index를 함께 설정합니다. 숫자는 1, 10, 100처럼 작고 정돈되게 유지하고, 9999를 쌓아 올리지 마세요. 
