position: sticky로 사이드바·목차 고정하기

사이드바-목차-고정하기


안녕하세요 이코노트허브 입니다.

긴 글을 읽다 보면 스크롤을 한참 내렸는데, 목차나 "맨 위로" 버튼이 화면 위쪽에 그대로 남아있어서 클릭 한 번에 원하는 곳으로 이동했던 경험 있으실 겁니다. 이런 효과를 position: sticky 속성 하나로 자바스크립트 없이 만들 수 있습니다.

[sticky, fixed와 뭐가 다를까요?]

고정 위치를 만드는 방법은 크게 두 가지가 있어서 헷갈리기 쉽습니다.

  • position: fixed: 화면(뷰포트) 기준으로 완전히 고정됩니다. 부모 요소가 어디에 있든 상관없이 항상 같은 위치에 붙어있습니다.
  • position: sticky: 평소엔 원래 자리에 있다가, 스크롤이 특정 지점을 지나면 그때부터 고정됩니다. 부모 요소의 범위 안에서만 고정된다는 점이 핵심입니다.

목차처럼 "본문 옆에서 같이 스크롤되다가, 화면 위쪽에 닿으면 그 자리에 멈추는" 효과를 원한다면 sticky가 훨씬 자연스럽습니다.

[기본 문법]

.toc {
  position: sticky;
  top: 20px;
}

top: 20px는 "화면 위쪽에서 20px 떨어진 지점에 닿으면 고정하라"는 뜻입니다. 스크롤을 내리다가 목차가 화면 위쪽 20px 지점에 도달하면, 그 위치에서 딱 멈춰서 계속 보이게 됩니다.

[실전 예제: 본문 옆 목차 고정하기]

<div class="post-layout">
  <div class="toc">
    <h3>목차</h3>
    <ul>
      <li><a href="#section1">1. 시작하기</a></li>
      <li><a href="#section2">2. 실전 예제</a></li>
      <li><a href="#section3">3. 마무리</a></li>
    </ul>
  </div>
  <div class="post-content">
    본문 내용...
  </div>
</div>
.post-layout {
  display: flex;
  gap: 24px;
  align-items: flex-start;
}

.toc {
  position: sticky;
  top: 20px;
  width: 220px;
  flex-shrink: 0;
}

.post-content {
  flex: 1;
}

여기서 align-items: flex-start를 부모(.post-layout)에 꼭 넣어야 합니다. 이게 없으면 flex 자식 요소들이 서로의 높이에 맞춰 늘어나면서, sticky가 원하는 대로 작동하지 않는 경우가 많습니다. flex-shrink: 0은 목차가 본문 내용에 밀려 좁아지지 않도록 막아줍니다.

[sticky가 작동하지 않을 때 체크리스트]

sticky는 특정 조건에서 조용히 작동을 멈추는 경우가 있어서, 초보자가 가장 자주 막히는 속성이기도 합니다.

  1. top 값을 안 준 경우: position: sticky;만 쓰고 top, bottom 중 아무것도 지정하지 않으면 고정되지 않습니다. 반드시 기준값을 함께 줘야 합니다.
  2. 부모 요소에 overflow: hidden(또는 auto)이 걸려있는 경우: 부모 요소가 스크롤 영역을 자체적으로 가지고 있으면, sticky가 그 부모 안에서만 작동하려다 오작동하는 경우가 많습니다. 부모의 overflow 속성을 확인해보세요.
  3. 부모 요소의 높이가 자식보다 작은 경우: sticky 요소는 부모의 세로 범위 안에서만 고정됩니다. 목차가 본문(부모)보다 세로로 더 길면 고정 효과가 이상하게 보일 수 있습니다.

[모바일에서는 끄는 게 나을 수도 있어요]

스마트폰처럼 화면이 좁을 땐, 목차를 옆에 나란히 둘 공간 자체가 없습니다. 지난번 배운 미디어 쿼리로 모바일에서는 sticky를 해제하는 것을 추천합니다.

@media (max-width: 768px) {
  .toc {
    position: static;
  }
}

position: static은 원래대로(고정 없이) 되돌리는 기본값입니다.

[초보자가 자주 하는 실수 2가지]

  1. fixed와 sticky를 섞어 쓰다 레이아웃이 깨지는 경우: fixed는 원래 자리를 완전히 벗어나 버려서, 다른 요소들이 그 공간을 채우려고 밀려옵니다. 반면 sticky는 원래 자리의 공간을 그대로 유지합니다. 목차처럼 "자기 자리는 지키면서" 고정하고 싶다면 sticky가 맞습니다.
  2. z-index 없이 다른 요소에 가려지는 경우: sticky 요소가 스크롤 중 다른 콘텐츠(이미지, 광고 등)에 가려 보이지 않을 수 있습니다. z-index: 10; 정도를 함께 지정해두면 항상 위에 표시됩니다.

핵심 요약

  • position: fixed는 화면 기준 완전 고정, position: sticky는 부모 범위 안에서 스크롤에 따라 고정됩니다.
  • sticky를 쓰려면 top 값을 반드시 함께 지정해야 합니다.
  • 부모 요소의 overflow나 높이 때문에 작동하지 않을 수 있으니, 안 되면 이 두 가지부터 확인하세요.
  • 모바일에서는 공간이 부족하므로 미디어 쿼리로 sticky를 해제하는 것이 좋습니다.

이미 블로그에 목차 기능을 만들어두셨다면, sticky 속성만 추가해도 스크롤 내내 목차가 따라다니는 훨씬 편리한 경험을 만들 수 있습니다.

댓글 쓰기

자유롭게 질문해주세요. 단, 광고성 댓글 및 비방은 사전 통보 없이 삭제됩니다.

다음 이전