Skip to content
This page has been auto-translated and may contain errors.View in English

위치 지정 및 z-index

docs.scrimba.com

상품 사진의 오른쪽 상단 모서리에 작은 "할인" 배지를 놓고 싶습니다. 페이지가 스크롤될 때 고정된 상태로 유지되는 헤더를 원합니다. 페이지의 다른 모든 것 위에 떠있는 대화 상자를 원합니다. 일반적인 CSS 간격은 요소를 하나씩 배열하기만 하므로 이 중 어느 것도 할 수 없습니다. 위치 지정은 요소를 그 일반적인 배열에서 벗어나 정확히 원하는 위치에 앉힐 수 있게 하는 도구의 집합입니다.

position 속성

모든 요소는 **static 위치 지정**으로 시작합니다. 이는 "페이지 흐름의 정상적인 위치에 앉아"라는 평범한 의미입니다. 이것이 기본값이며 대부분의 경우 원하는 것입니다. 위치 지정은 요소를 그 정상적인 위치에서 벗어나게 하려는 경우에 중요해집니다.

다음 단계는 position: relative입니다. 요소를 정상적으로 놓일 위치에서 이동시키며, 네 가지 오프셋 속성을 사용합니다: top, right, bottom, left. 핵심은 요소가 원래 공간을 유지한다는 것입니다. 다른 것은 공백을 채우기 위해 움직이지 않습니다.

css
.badge {
  position: relative;
  top: 10px;                 /* 정상적인 위치에서 아래쪽으로 10px 밀림 */
  left: 20px;                /* 정상적인 위치에서 오른쪽으로 20px 밀림 */
}

static 요소에 대해서는 topleft 오프셋이 전혀 작동하지 않습니다. positionstatic 이외의 것으로 설정한 후에야 작동합니다.

페이지의 모든 것은 position: static으로 시작하며, display 및 문서 흐름에서 만난 정상적인 위에서 아래로의 흐름에 있습니다. Static 요소는 오프셋 속성을 완전히 무시하므로 top 또는 left를 설정해도 아무것도 하지 않습니다. 이는 사람들을 혼동시킵니다: top: 20px을 추가하고 변화가 없으면, 값이 잘못되었다고 가정하지만 실제 문제는 position이 누락된 것입니다.

온화한 선택지는 **relative 위치 지정**입니다. 이는 정상적인 위치에서 제공한 오프셋만큼 요소를 이동시키면서 원래 공간을 예약된 상태로 유지합니다. 이웃들은 공백을 채우기 위해 움직이지 않으므로 relative 위치 지정된 요소는 옆에 있는 것과 겹칠 수 있습니다.

css
.tooltip {
  position: relative;
  top: -4px;                 /* 놓일 위치에서 위로 4px 들어올림 */
  left: 8px;                 /* 오른쪽으로 8px 밀림 */
  /* 예약된 공간은 그대로 유지됨; 그리기만 이동 */
}

top, left와 같은 오프셋은 요소가 위치 지정된 후에만 적용됩니다. 그 자체로는 relative는 작은 이동 도구입니다. 더 중요한 역할은 절대 위치 지정된 자식의 참조점을 설정하는 것이며, 이것이 다음 섹션입니다.

position 속성은 다섯 가지 값을 가지며, 하나의 질문으로 나누면 모델 전체를 더 쉽게 이해할 수 있습니다: 요소가 여전히 정상 흐름에서 공간을 차지합니까? static(초기값)과 **relative**는 모두 그렇고, absolutefixed는 그렇지 않으며, sticky는 스크롤할 때 두 동작 사이를 전환하는 하이브리드입니다.

relativestatic에서 가장 가벼운 이탈입니다. 요소는 static인 것처럼 정상 흐름에 정확히 배치되고, 원래 위치에서 공간이 예약되며, 그 다음 top / right / bottom / left로 그 위치에서 시각적으로 이동됩니다. 예약된 공간이 움직이지 않으므로 relative 요소를 오프셋하면 그리기 위치만 변경되고 레이아웃이 생각하는 위치는 변경되지 않으므로 인접한 콘텐츠와 겹칠 수 있습니다.

css
.list-item {
  position: relative;
  top: 6px;                  /* 6px 더 낮게 그려짐; 흐름 슬롯은 유지됨 */
}

두 가지 정밀한 포인트가 있습니다. 첫째, 오프셋은 요소 자신의 정상 위치에 대해 확인되며, 조상에 대해서가 아닙니다: top: 10px은 "당신이 이미 있는 위치에서 아래로 10px"이지, "컨테이너 상단에서 10px"이 아닙니다. 둘째, 상대 요소에 대해 반대 오프셋(topbottom, 또는 leftright)을 설정하면, 왼쪽에서 오른쪽으로, 위에서 아래로 쓰는 모드에서 시작 쪽이 우선하므로 topbottom을 재정의하고 leftright를 재정의합니다. relative를 선택하는 훨씬 더 일반적인 이유는 이동이 아니라 absolute 자식을 위한 포함 블록을 확립하는 것이며, 다음 섹션에서 이를 자세히 설명합니다.

Junoposition 속성 모든 것은 static으로 시작하므로 정상적인 위치에 앉아 있습니다. position: relative로 전환하면 top, right, bottom, left로 이동시킬 수 있으면서도 원래 공간은 예약됩니다. 오프셋 속성은 요소가 위치 지정될 때까지 아무것도 하지 않으므로, top이 무시되는 것처럼 보이면 먼저 position을 설정했는지 확인하세요.
Junoposition 속성static은 기본값이며 오프셋을 완전히 무시하므로, 일반 요소에 top: 20px를 설정해도 아무것도 하지 않습니다. relative는 정상적인 위치에서 요소를 이동시키면서 공간을 유지하므로 이웃이 공백을 채우기 위해 이동하지 않습니다. 이동은 편리하지만, relative를 선택하는 실제 이유는 다음에 올 절대 위치 지정 자식을 고정시키기 위해서입니다.
Junoposition 속성 다섯 가지 값을 흐름에 공간을 유지하는지 여부로 정렬하세요: staticrelative는 유지하고, absolutefixed는 유지하지 않으며, sticky는 둘 사이를 전환합니다. relative 오프셋은 요소의 정상 위치에 대해 확인되며, 컨테이너에 대해 아니고, 반대 오프셋은 시작 쪽이 우승하게 합니다. relative를 이동 도구보다 절대 자식의 앵커로 훨씬 더 자주 사용할 것입니다.

Absolute 위치 지정

position: absolute는 더 큰 이동입니다. 이는 요소를 정상 흐름에서 깨끗이 들어올리므로 더 이상 공간을 차지하지 않으며, 주변 요소들은 마치 존재하지 않았던 것처럼 접혀집니다. 그 다음 동일한 top, right, bottom, left 오프셋을 사용하여 요소를 배치합니다.

질문은: 무엇에 대한 오프셋입니까? absolute 요소는 가장 가까운 위치 지정된 조상 즉, static 이외의 position을 가진 가장 가까운 부모에 대해 자신을 위치 지정합니다. 이것이 배지-온-카드 패턴이 항상 쌍으로 나오는 이유입니다: 카드를 relative로 만들어서 참조점이 되게 한 다음 배지를 absolute로 만들어서 카드의 모서리에 앉을 수 있게 합니다.

css
.card {
  position: relative;        /* 참조점이 됨 */
}

.card .badge {
  position: absolute;
  top: 8px;                  /* 카드 상단에서 8px */
  right: 8px;                /* 카드 오른쪽에서 8px */
}

카드에 position: relative가 없으면 배지는 페이지 위쪽의 위치 지정된 조상을 찾아서 의도하지 않은 어딘가에 착륙할 것입니다.

**Absolute 위치 지정**은 요소를 정상 흐름에서 완전히 제거합니다. 공간을 차지하지 않고, 이전 이웃들은 마치 사라진 것처럼 함께 붕괴하며, 그 다음 오프셋 속성으로 배치합니다. 오프셋은 요소의 포함 블록에 대해 측정됩니다: 자신도 위치 지정된 가장 가까운 조상의 패딩 모서리입니다.

그 "가장 가까운 위치 지정된 조상" 규칙은 끊임없이 사용할 패턴의 핵심입니다. 부모를 position: relative로 설정하세요(이는 그 자체로 시각적 변화를 일으키지 않음), 그러면 내부의 모든 absolute 자식의 참조 프레임이 됩니다.

css
.dropdown {
  position: relative;        /* 참조 프레임, 시각적 변화 없음 */
}

.dropdown .menu {
  position: absolute;
  top: 100%;                 /* 트리거 바로 아래 */
  left: 0;                   /* 왼쪽 모서리에 정렬 */
  width: 200px;
}

조상이 위치 지정되지 않으면 absolute 요소는 초기 포함 블록(대략 뷰포트)으로 돌아가고 일반적으로 페이지의 왼쪽 상단에 착륙합니다. 위치가 잘못된 absolute 요소는 거의 항상 의도한 부모에 누락된 position: relative입니다.

절대 위치 지정된 요소는 정상 흐름에서 제거됩니다: 흐름에 상자를 생성하지 않고, 부모의 높이에 기여하지 않으며, 형제들은 존재하지 않는 것처럼 배치합니다. 그 다음 포함 블록에 대해 위치 지정되며, 포함 블록 규칙을 정확히 하는 것이 "작동함"과 "작동하고 이유를 앎"을 구분합니다.

absolute 요소의 경우, 포함 블록은 positionstatic이 아닌 가장 가까운 조상의 패딩 박스입니다. 여러 조상이 자격이 있으면, 가장 가까운 것이 우승합니다. 없으면, 포함 블록은 초기 포함 블록이며, 문서에 고정된 뷰포트 크기 직사각형입니다. 이것이 고정되지 않은 absolute 요소가 페이지의 왼쪽 상단으로 떠내려가는 이유입니다.

css
.field {
  position: relative;        /* 포함 블록을 확립 */
  padding: 12px;
}

.field .clear-button {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);   /* .field에 대해 수직 중심 */
  /* 오프셋은 .field의 콘텐츠 박스가 아닌 패딩 박스에서 측정됨 */
}

한 가지 규칙이 사람들을 놀라게 하고 고급 포함 블록 그림에서 중요합니다: 조상의 transform, filter, 또는 will-changeposition이 설정되지 않았어도 절대 자식을 위한 포함 블록을 확립합니다. 따라서 absolute 자식은 갑자기 의도하지 않은 변환된 조부모로 부모를 바꿀 수 있습니다. absolute 요소가 "잘못된" 요소에 대해 위치 지정할 때, position이 누락된 것뿐만 아니라 트리 위의 잘못된 transform을 확인하세요.

JunoAbsolute 위치 지정position: absolute는 요소를 흐름에서 끌어내므로 공간을 차지하지 않고 이웃들이 뒤로 이어집니다. 그 다음 position이 설정된 가장 가까운 부모에 대해 위치 지정합니다. 이것이 배지-온-카드 트릭이 쌍인 이유입니다: 카드에 relative, 배지에 absolute, 그래서 배지가 카드의 모서리에 착륙하고 임의의 어딘가가 아닙니다.
JunoAbsolute 위치 지정 absolute 요소는 완전히 흐름을 벗어나고 포함 블록, 자신도 위치 지정된 가장 가까운 조상에 대해 위치 지정합니다. 일상적인 패턴은 부모의 position: relative이며, 시각적으로는 아무것도 변경하지 않지만 참조 프레임이 됩니다, 그 다음 자식의 absolute입니다. absolute 요소가 페이지의 왼쪽 상단 모서리에 착륙하면, 조상이 위치 지정되지 않았고 뷰포트로 돌아갔다는 의미입니다.
JunoAbsolute 위치 지정 absolute 요소의 포함 블록은 가장 가까운 non-static 조상의 패딩 박스이거나, 없으면 뷰포트입니다. 함정은 transform, filter, will-changeposition 없이 포함 블록을 생성하므로, 자식은 당신이 잊은 변환된 조부모에 고정될 수 있다는 것입니다. 오프셋이 잘못된 요소에 착륙할 때, 누락된 position뿐만 아니라 트리의 잘못된 transform을 스캔하세요.

Fixed 및 sticky

position: fixed는 요소를 화면 자체에 고정시킵니다. absolute처럼 흐름을 벗어나지만, 부모에 고정되는 대신 뷰포트(보이는 창)에 고정됩니다. 고정되면 페이지를 스크롤해도 화면의 같은 위치에 유지됩니다. 이것이 네비게이션 바 또는 "맨 위로 돌아가기" 버튼이 항상 보이는 방식입니다.

css
.site-header {
  position: fixed;
  top: 0;                    /* 창 상단에 고정 */
  left: 0;
  right: 0;                  /* 전체 너비에 걸쳐 확장 */
}

position: sticky는 우호적인 중간 지대입니다. sticky 요소는 일반적으로 페이지와 함께 스크롤되다가 설정한 임계값에 도달하면 제자리에 붙습니다. 콘텐츠와 함께 스크롤되었다가 화면 상단에 고정되는 섹션 제목이 고전적인 예입니다.

css
.section-title {
  position: sticky;
  top: 0;                    /* 상단 모서리에 도달하면 붙음 */
}

**Fixed 위치 지정**은 absolute처럼 작동하지만, 포함 블록이 조상이 아닌 항상 뷰포트입니다. fixed 요소는 흐름에서 제거되고 화면의 고정된 위치에 고정되므로, 페이지가 스크롤될 때 움직이지 않습니다. 이는 지속적인 크롬(persistent chrome)의 도구입니다: 상단 바, 쿠키 배너, 떠다니는 액션 버튼.

css
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 64px;
  /* 아래 콘텐츠는 숨겨지지 않도록 padding-top: 64px 필요 */
}

이 주석은 주요 장애물을 지시합니다. fixed 헤더는 흐름에서 벗어나기 때문에 아래의 콘텐츠와 겹치므로, 일반적으로 페이지 본문에 일치하는 패딩이나 마진을 추가하여 콘텐츠를 밀어냅니다.

Sticky 위치 지정은 하이브리드입니다: 요소는 뷰 내에 있는 동안 relative처럼 동작한 다음 top, bottom, left, right로 설정한 임계값에 도달하면 fixed 같은 동작으로 전환합니다. threshold 오프셋이 없는 sticky 요소는 붙을 선이 없으므로 붙지 않습니다.

css
.section-title {
  position: sticky;
  top: 16px;                 /* 도달하면 상단에서 16px 거리 유지 */
}

fixedabsolute에 중요한 한 가지 차이가 있습니다: 포함 블록이 뷰포트이므로 화면에 고정되고 문서와 함께 스크롤하지 않습니다. 이는 지속적인 UI에 적합하지만 두 가지 주의사항이 있습니다. 흐름 내 콘텐츠와 겹쳐서 (본문에 패딩을 예약하여) 해결하고, 절대 위치 지정과 동일한 transform-포함-블록-설정 규칙이 여기에도 적용되므로 조상 transformfixed 요소를 그 조상 내에 갇혀서 함께 스크롤합니다. "고정된" 요소가 신비하게 스크롤되면 거의 항상 변환된 조상 아래에 있습니다.

**Sticky 위치 지정**은 다섯 개 중 가장 조건부적입니다. sticky 요소는 정상 흐름에 배치되어 공간을 유지하고, 가장 가까운 스크롤 가능한 조상이 선언한 임계값까지 스크롤할 때까지 거기 유지됩니다; 그 지점부터 포함 블록이 스크롤되어 지나갈 때까지 임계값에 고정되고, 그 지점에서 해제됩니다. 사람들이 놓치는 두 가지 요구사항:

css
.toc {
  position: sticky;
  top: 24px;                 /* 임계값; 오프셋이 없으면 붙지 않음 */
  /* .toc의 부모가 화면에 있는 동안만 붙음 */
}

첫째, sticky는 threshold 오프셋(top, bottom, left, right)을 필요로 하며, 없으면 잡을 선이 없고 일반 relative 요소처럼 동작합니다. 둘째, 부모의 경계 내에서만 붙을 수 있으므로, 부모가 짧으면 부모가 뷰 밖으로 스크롤되는 즉시 붙지 않습니다. 그리고 자주 조용한 실패: overflow: hidden, scroll, auto를 가진 조상이 sticky 요소의 스크롤 컨테이너가 되므로, sticky 항목은 예상한 것이 아닌 컨테이너 내에 있기 때문에 조용하게 아무것도 하지 않을 수 있습니다.

JunoFixed 및 stickyposition: fixed는 요소를 화면에 고정시키므로 스크롤할 때도 그대로 유지되며, 이것이 헤더 또는 맨 위로 가기 버튼이 유지되는 방식입니다. position: sticky는 중간 지대입니다: 페이지와 함께 스크롤되었다가 top: 0 같은 임계값에 도달하면 붙습니다. Fixed는 또한 아래의 것과 겹치므로 콘텐츠를 위해 공간을 남겨두세요.
JunoFixed 및 stickyfixed는 뷰포트에 고정된 absolute이므로 페이지가 스크롤될 때 화면에 유지되지만, 주변에 패딩하지 않으면 흐름 내 콘텐츠와 겹칩니다. sticky는 임계값 오프셋에 도달할 때까지 relative처럼 동작한 다음 제자리에 고정됩니다. 설정된 top 또는 bottom이 없는 sticky 요소는 잡을 선이 없으므로 붙지 않습니다.
JunoFixed 및 stickyfixed는 뷰포트에 고정되지만 조상 transform이 내부에 갇혀서 스크롤하므로, 스크롤하는 "고정된" 요소는 보통 변환된 부모를 가집니다. sticky는 사람들이 잊는 두 가지를 필요로 합니다: threshold 오프셋과 충분히 큰 부모, 왜냐하면 부모가 스크롤되는 순간 해제되기 때문입니다. 그리고 overflow가 설정된 조상을 주시하세요. 이것이 스크롤 컨테이너가 되고 sticky를 조용하게 작동 중지시킬 수 있습니다.

z-index로 쌓기

요소가 겹치면, 어느 것이 위에 있는지 결정해야 합니다. 이것이 z-index가 제어하는 것입니다. 더 높은 z-index는 더 낮은 것 앞에 그려지므로, z-index: 10인 드롭다운이 z-index: 1인 카드를 덮습니다.

모두를 난처하게 하는 한 가지 규칙이 있습니다: z-index는 위치 지정된 요소에서만 작동합니다. 요소가 여전히 static이면, z-index는 무시됩니다. 따라서 거의 항상 positionz-index를 함께 설정합니다.

css
.modal {
  position: fixed;
  z-index: 100;              /* 정상적인 페이지 콘텐츠 위에 앉음 */
}

.modal-overlay {
  position: fixed;
  z-index: 99;               /* 어두운 배경, 모달 뒤 한 단계 */
}

보통 여기서 큰 숫자가 필요하지 않습니다. 9999를 가득 채운 페이지보다 1, 10, 100 같은 작고 정돈된 척도가 이유하기 더 쉽습니다.

두 요소가 겹칠 때, z-index는 앞에서 뒤로의 순서를 설정합니다: 높은 숫자가 낮은 숫자 위에 그려집니다. 함정은 **z-index는 위치 지정된 요소에만 영향**을 미친다는 것입니다. static 요소에 z-index를 주면 아무것도 일어나지 않으므로, z-indexposition은 거의 항상 함께 이동합니다.

css
.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
}

.tooltip {
  position: absolute;
  z-index: 50;               /* 카드 위, 모달 아래 */
}

일찍부터 형성할 가치 있는 습관은 증가하는 숫자보다 작고 의도적인 척도입니다. z-index: 9999를 쓰려고 할 때 뭔가를 이기기 위해, 실제 해결책은 보통 더 큰 숫자가 아닌 쌓기 값에 대한 계획입니다. 다음 레벨은 더 큰 숫자가 어떤 때는 여전히 왜 패배하는지 설명합니다.

z-index는 겹친 위치 지정된 요소를 z축을 따라 정렬하며, 더 높이 앞으로, static 요소에서는 무시됩니다. 5분 버그를 1시간으로 바꾸는 부분은 쌓기 컨텍스트입니다: z-index 값이 비교되는 자체 포함 그룹이며, 형제에 대해 단일 단위로 쌓입니다.

쌓기 컨텍스트는 요소가 z-index auto 이외의 값으로 위치 지정될 때마다 형성되지만, 1보다 낮은 opacity, 모든 transform, filter, will-change, isolation: isolate, 그리고 몇 개의 다른 것들로부터도 형성됩니다. 중요하게, z-index동일한 쌓기 컨텍스트 내에서만 비교됩니다. 요소가 컨텍스트 내에 앉으면, z-index는 그것이 아무리 크더라도 그 컨텍스트 밖의 어떤 것도 위에 올라올 수 없습니다.

css
.card {
  opacity: 0.98;             /* 이것만으로도 쌓기 컨텍스트 생성 */
}

.card .badge {
  position: absolute;
  z-index: 9999;             /* .card의 컨텍스트 내에 갇힘 */
}

.sibling-panel {
  position: relative;
  z-index: 2;                /* 여전히 .badge 위에 그려짐 */
}

여기 9999.badge2.sibling-panel에 패배합니다. .badge.cardopacity가 생성한 컨텍스트 내에 갇혀있고, 그 전체 컨텍스트가 .sibling-panel 아래로 순위 매겨지기 때문입니다. 높은 z-index가 우승하기를 거부할 때, 답은 거의 절대 더 높은 숫자가 아니라, 조용하게 쌓기 컨텍스트를 열었던 조상 (보통 opacity 또는 transform)이며, 해결책은 그 조상을 올리거나 격리하는 것입니다.

위치 지정과 z-index에 대한 판단에 대한 마지막 포인트: 이들은 오버레이, 배지, 고정된 크롬, 흐름을 벗어나거나 위에 앉아야 하는 것들을 위한 것입니다. 페이지의 주요 구조를 배열하는 데는 잘못된 도구입니다. 콘텐츠와 뷰포트에 반응해야 하는 행, 열, 그리드는, flexbox 또는 박스 모델의 박스 모델 주도 흐름에 도달하고, 위에 떠있는 레이어를 위해 위치 지정을 유지하세요.

Junoz-index로 쌓기 요소가 겹칠 때, z-index는 어느 것이 앞에 있는지 결정합니다: 더 높은 숫자가 우승합니다. 위치 지정된 요소에서만 작동하므로, 일반 static 요소의 z-index는 무시되며, positionz-index를 함께 설정합니다. 9999 더미 대신 1, 10, 100 같은 작고 정돈된 숫자를 유지하세요.
Junoz-index로 쌓기z-index는 위치 지정된 요소의 앞에서 뒤로의 순서를 설정하며, static 요소에서는 아무것도 하지 않으므로, position과 함께 이동합니다. 증가하는 숫자보다 작고 의도적인 척도에 도달하세요; 9999를 쓰려고 할 때, 실제 해결책은 보통 더 큰 숫자가 아닌 계획입니다. 그리고 때로 더 큰 숫자가 여전히 패배하는데, 그에 대해 심화 과정의 쌓기 컨텍스트가 설명합니다.
Junoz-index로 쌓기z-index는 쌓기 컨텍스트 내에서만 비교되며, opacity 1보다 낮음, transform, filter 같은 것들이 조용하게 하나를 생성합니다. 그것이 z-index: 9999의 자식이 여전히 바깥 요소의 2에 패배할 수 있는 이유입니다: 그것이 조상의 컨텍스트 내에 갇혀있습니다. 높은 숫자가 우승하지 않으면 컨텍스트를 열었던 조상을 찾아서 올리고, 페이지 레이아웃보다 오버레이를 위해 위치 지정을 유지하세요.