인턴

[ Troubleshooting🛠️ ] sticky 포지션과 overflow: hidden 충돌 해결하기

choijming21 2025. 4. 21. 18:22

1.  문제 발생❓

 Next.js 프로젝트에서 랜딩 페이지 템플릿을 개발하던 중, 페이지 최상단에 overflow: hidden 속성을 추가하고 싶었으니 이를 적용하자 Lnb 컴포넌트(sticky 네비게이션 바)가 제대로 동작하지 않는 문제가 발생했습니다.

 

// 문제가 있는 코드
export default function Template({ userInfo }: Props) {
  // ... 코드 생략 ...
  
  return (
    <div style={{ backgroundColor: vars.neutral[100], overflow: 'hidden' }}>
      <GNB />
      <Hero {...heroProps} />
      <Lnb menus={LNB_ITEMS} course={course} />
      {/* 나머지 콘텐츠 */}
    </div>
  );
}

 

 

 

 

2.  원인 추론 🔎

해당 문제의 원인은 CSS positon: sticky와 overflow: hidden 사이의 상호작용에 있었습니다. 

  • Lnb 컴포넌트는 내부적으로 position: sticky를 사용하여 스크롤 시 화면 상단에 고정되도록 설계되어 있습니다.
  • 상위 컨테이너에 overflow: hidden을 적용하면 새로운 스태킹 컨텍스트(stacking context)가 생성됩니다.
  • 이로 인해 position: sticky 요소는 뷰포트가 아닌 가장 가까운 스크롤 컨테이너(이 경우 overflow: hidden이 적용된 부모)에 대해 sticky 동작을 수행하게 됩니다.
  • 결과적으로 sticky 네비게이션 바가 예상대로 스크롤에 따라 고정되지 않고 비정상적으로 동작했습니다.

여기서 position: sticky란?

  • position: sticky는 CSS 포지셔닝 속성으로, 일반 요소와 고정된 요소의 특성을 모두 가진 하이브리드 같은 속성입니다. 쉽게 설명하자면, 사용자가 스크롤하는 동안 특정 지점에 도달하면 화면에 '붙어서' 따라오는 요소를 만들 수 있습니다.

작동 방식

  1. 처음에는 보통 요소처럼 페이지 흐름에 따라 있습니다.
  2. 스크롤하다가 지정한 위치(ex: top: 0)에 도달하면
  3. 그 위치에 "붙어서" 화면을 따라다닙니다.
  4. 그러다가 부모 요소의 끝에 도달하면 다시 일반적인 흐름을 따릅니다.

간단한 예시

.nav-bar {
  position: sticky;
  top: 0; /* 화면 상단에 도달하면 거기에 붙습니다 */
}

 

주의할 점

  • 부모 요소에 overflow: hidden이 있으면 sticky가 제대로 작동하지 않을 수 있습니다.
  • top, right, bottom, left 중하나 이상을 반드시 지정해야 합니다.
  • 요소는 부모 컨테이너 범위 내에서만 sticky 효과가 있습니다.

이렇게 sticky는 스크롤 중에도 계속 보여야 하는 네비게이션 바, 섹션 제목, 필터 등을 만들 때 매우 유용합니다!

 

 

 

3.  해결 과정 📋

이 문제를 해결하기 위해 페이지 구조를 변경하여 overflow: hidden과 position: sitcky가 서로 충돌하지 않도록 했습니다.

  • 최상위 div에 overflow: hidden을 적용하는 대신, sticky 요소인 Lnb 아래에 새로운 Wrapper div를 추가하고 그 안에 모든 콘텐츠를 배치했습니다.
  • Lnb는 부모에 overflow: hidden이 없으므로 sticky 포지셔닝 뷰포트를 기준으로 정상 작동합니다.
  • 그 외 모든 콘텐츠는 overflow: hidde이 적용된 컨테이너 안에 위치하므로 원하는 스타일링이 적용됩니다.
export default function Template({ userInfo }: Props) {
  // ... 코드 생략 ...
  
  return (
    <div style={{ backgroundColor: vars.neutral[100] }}>
      <Portal selector='#portal'>
        {/* 포털 컨텐츠 */}
      </Portal>
      <GNB />
      <Hero {...heroProps} />
      <Lnb menus={LNB_ITEMS} course={course} />
      
      {/* LNB 아래의 콘텐츠에 대해 overflow: hidden이 있는 래퍼 div 추가 */}
      <div style={{ width: '100%', overflow: 'hidden' }}>
        {/* 나머지 모든 콘텐츠 */}
        <div attribute={TARGET_DATA.introduction}>
          <Promotion courseType={course} />
          {/* 다른 컴포넌트들... */}
        </div>
        
        {/* 나머지 섹션들... */}
        
        <Footer />
        <ChannelTalkBtn />
      </div>
    </div>
  );
}

 

 

 

 

 

4.  결론 ❤‍🔥

CSS 스택킹 컨텍스트 이해하기:

  • overflow: hidden, position: fixed/sticky, z-index 등의 속성은 새로운 스택킹 컨텍스트를 생성하며, 이는 자식 요소의 동작에 영향을 미칠 수 있습니다!