---
title: "sticky 가 조용히 죽는 자리, overflow:hidden 은 스크롤하지 않아도 scrollport 다"
description: "같은 컴포넌트인데 iframe 화면에서만 position:sticky 가 먹지 않았던 원인은 루트의 overflow:hidden 이었습니다. 스크롤 컨테이너 기준과 flex 높이 협상의 함정까지 다룹니다."
date: 2026-10-08
updated: 2026-10-08T08:37:49.112Z
tags: [css, sticky, overflow, iframe]
canonical: https://blog.wooncloud.com/posts/sticky-overflow-hidden-scrollport
---

목록 위에 붙는 액션 바를 `position: sticky; top: 0` 으로 고정했는데, 같은 컴포넌트가 한 화면에서는 잘 붙고 다른 화면에서는 스크롤하면 그대로 밀려 올라가 사라졌습니다.

잘 되는 쪽은 일반 페이지였고, 안 되는 쪽은 iframe 으로 다른 서비스에 끼워 넣은 화면이었습니다. 마크업도 스타일도 똑같은데 말이죠.

## 처음 세운 가설은 틀렸습니다

"iframe 바깥(호스트 페이지)이 스크롤하니까 iframe 안의 sticky 는 원리적으로 못 붙는다"고 생각했습니다. 그럴듯하지만 틀렸습니다.

실제 원인은 임베드용 셸 루트에 있던 한 줄이었습니다.

```css
/* 임베드 셸 루트 */
min-height: 100vh;
overflow: hidden;   /* ← 이것 */
```

**`overflow` 가 `visible` 이 아닌 요소는 스크롤이 실제로 일어나는지와 상관없이 scroll container(scrollport)가 됩니다.** `sticky` 는 가장 가까운 스크롤 컨테이너를 기준으로 동작하니, 이 div 가 기준이 됩니다.

그런데 이 div 는 높이가 콘텐츠만큼 자라 있어서 자기 안에서는 스크롤이 일어나지 않습니다. 기준 축이 한 번도 움직이지 않으니 sticky 는 아무 일도 하지 않고, 정작 스크롤되는 건 그 바깥(문서)이라 바가 통째로 밀려 올라갑니다.

잘 되던 쪽에는 중간에 `overflow: auto` 인 진짜 스크롤 컨테이너가 한 겹 있었습니다. 둘의 유일한 차이였습니다.

![sticky 바의 기준이 overflow hidden 인 셸 루트 div 라 스크롤이 일어나지 않아 바가 밀려 올라가고, main 에 overflow auto 를 두면 그 안에서 스크롤이 일어나 바가 붙어 있는다.](/images/posts/sticky-overflow-hidden-scrollport/98b1067d-7a7f-43f6-be41-9015a6bb4cda.svg)

## 스크롤 축을 가진 요소를 직접 둡니다

sticky 를 쓰는 화면에서는 스크롤 축을 소유한 요소를 명시적으로 둡니다.

```html
<div style="height:100%; display:flex; flex-direction:column; overflow:hidden">
  <main style="flex:1; min-height:0; overflow:auto">
    <div style="position:sticky; top:0">액션 바</div>
    <!-- 목록 -->
  </main>
</div>
```

`min-height: 0` 이 빠지면 flex 아이템의 기본값(`auto`)이 축소를 막아서 스크롤이 생기지 않습니다. 자주 빠뜨리는 짝이라 같이 챙겨야 합니다.

## 곁다리, iframe 높이를 알려 주는 프로토콜은 반영을 보장하지 않습니다

이 화면은 콘텐츠 높이가 바뀔 때마다 `postMessage` 로 높이를 호스트에 알리고, 호스트가 `iframe.style.height` 를 설정하는 구조였습니다. 그래서 프레임이 콘텐츠만큼 길어져 있다고 가정했는데, 직접 재 보니 아니었습니다.

호스트의 컨테이너가 flex 였고 iframe 에 `flex: 1 1 auto` 가 걸려 있었습니다. `flex-shrink: 1` 이라 명시한 height 가 컨테이너 높이로 되돌아옵니다. 5,440px 을 요청했는데 실제로는 640px 이었습니다.

![postMessage 로 5,440px 를 요청해도 flex 컨테이너가 줄이면 실제 높이는 640px 로 되돌아간다.](/images/posts/sticky-overflow-hidden-scrollport/16dc0ec7-9dee-4e94-9131-0d312a259d3a.webp)

높이 협상 프로토콜이 있다고 해서 그 값이 적용되는 건 아닙니다. flex/grid 컨테이너 안에서 `height` 는 결정이 아니라 요청입니다.

그리고 이런 판단은 읽어서 추론하지 말고 재야 합니다. 호스트의 CSS 체인을 복제한 페이지를 만들어 헤드리스 브라우저로 세 가지 변형을 나란히 측정했습니다. 스크롤 600px 뒤 액션 바의 화면 좌표는 이랬습니다.

| 변형 | 액션 바 좌표 |
| --- | --- |
| 현행 | -520px |
| overflow 제거 | 80px |
| 스크롤 컨테이너 도입 | 80px |

20분짜리 프로브가 가설 하나를 뒤집었네요.

## 참고

- [MDN position: sticky](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky)
- [CSS Overflow Module Level 3 scroll container](https://www.w3.org/TR/css-overflow-3/#scroll-container)
- [MDN flex 아이템의 auto 최소 크기](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Mastering_wrapping_of_flex_items)
