스티키 헤더

Sticky header

스크롤을 내려도 화면 위쪽에 계속 붙어 있는 헤더. `position: sticky` 한 줄로 만듭니다.

다른 이름: Fixed headerPinned header
···
html
<div class="phone">
  <div class="scroller" id="scroller">
    <header>Header — sticky top:0</header>
    <div class="body">
      <i class="ln"></i><i class="ln"></i><i class="ln"></i><i class="ln"></i>
      <i class="ln"></i><i class="ln"></i><i class="ln"></i><i class="ln"></i>
      <i class="ln"></i><i class="ln"></i><i class="ln"></i><i class="ln"></i>
    </div>
  </div>
</div>
css
.phone{width:min(60%,220px);height:min(92%,300px);border:1px solid var(--line);border-radius:16px;overflow:hidden;
  box-shadow:0 8px 24px rgba(0,0,0,.12);background:var(--bg)}
.scroller{height:100%;overflow-y:auto;scrollbar-width:none}
.scroller::-webkit-scrollbar{display:none}
header{position:sticky;top:0;background:var(--accent);color:#fff;font-size:11px;font-weight:700;
  padding:12px;text-align:center;z-index:1}
.body{padding:14px;display:flex;flex-direction:column;gap:14px}
.ln{display:block;height:14px;border-radius:4px;background:var(--surface);border:1px solid var(--line)}
js
const scroller = document.getElementById('scroller');
let dir = 1;
function tick() {
  const max = scroller.scrollHeight - scroller.clientHeight;
  scroller.scrollTop += dir * 1.1;
  if (scroller.scrollTop >= max) dir = -1;
  if (scroller.scrollTop <= 0) dir = 1;
  requestAnimationFrame(tick);
}
requestAnimationFrame(tick);

`position: fixed`는 요소를 아예 스크롤 흐름에서 빼내 항상 같은 자리에 고정하지만, `position: sticky`는 "원래 자리에 있다가, 스크롤로 그 지점을 지나면 고정된다"는 하이브리드 동작을 합니다. 그래서 헤더가 페이지 맨 위에서는 평범하게 흐르다가 스크롤 시점부터 딱 붙습니다.

필요한 건 세 가지뿐입니다: `position: sticky`, `top: 0`(붙을 위치), 그리고 부모 요소에 `overflow: hidden`이 없어야 한다는 것(있으면 sticky가 동작하지 않습니다). z-index도 신경 써야 아래 콘텐츠가 헤더 위로 올라오지 않습니다.

스크롤 방향에 따라 헤더를 숨겼다 보여주는 패턴(아래로 스크롤하면 숨김, 위로 올리면 다시 표시)은 sticky만으로는 안 되고 스크롤 이벤트를 감지해 `transform: translateY`를 추가로 제어해야 합니다.

언제 쓰나

내비게이션이나 검색·필터처럼 스크롤 중에도 계속 손닿는 곳에 있어야 하는 컨트롤에 씁니다. 화면이 작은 모바일에서는 헤더가 콘텐츠를 너무 많이 가리지 않도록 높이를 낮추세요.