컴포넌트/패널 외 영역 (Div, Span)

StickyDiv (스틱키디비전)

VanillaFront 2026. 9. 20. 16:10

Va.StickyDiv — 스크롤 시 고정되는 Sticky 컨테이너

스크롤해도 화면 특정 위치에 고정되는(sticky) 컨테이너입니다. CSS position: sticky를 자동 적용하며, position 속성으로 top/bottom/left/right 중 고정 위치를 지정할 수 있습니다.

클래스 정보

Va.StickyDiv extends Va.Component
tagName: 'stickyDiv' (실제 렌더링은 <div>)
isContainer: true

Va.Div가 아니라 Va.Component를 직접 상속하지만, CSS 클래스는 va-div sticky가 부여되어 Div 계열 스타일을 재사용합니다.

기본 사용법

{
    tagName: 'stickyDiv',
    position: 'top',
    style: { background: 'var(--colorBackground)', padding: '10px' },
    tags: [
        { tagName: 'title', innerHTML: '스크롤해도 상단 고정' }
    ]
}

또는 코드로:

let sticky = new Va.StickyDiv({
    position: 'top',
    innerHTML: '<h3>고정 헤더</h3>'
});
parent.append(sticky);

CSS position: sticky 동작 원리

position: sticky는 CSS의 하이브리드 포지션:

  • 스크롤이 지정 위치에 도달하기 전까지는 일반 요소처럼 동작
  • 지정 위치에 도달하면 fixed처럼 화면에 고정
  • 부모 컨테이너 밖으로는 나가지 않음 (스크롤이 부모를 벗어나면 함께 사라짐)

즉 "스크롤에 따라 붙는 위치가 바뀌는" UI에 최적:

  • 테이블 헤더가 스크롤 시 상단에 붙음
  • 사이드바가 스크롤과 함께 움직이다가 특정 지점에서 고정
  • 하단 액션 바가 항상 화면 하단에 노출

속성

속성타입설명

position String 'top', 'bottom', 'left', 'right' — 고정 방향
stopPropagation Boolean 클릭 이벤트 전파 차단 여부
innerHTML String HTML 문자열
layout, style, class, hidden, attributes 공통 속성

position별 기본 offset

CSS로 자동 적용되는 기본 offset (3rem = 대략 30px):

positionCSS

'top' top: 3rem
'bottom' bottom: 3rem
'left' left: 3rem
'right' right: 3rem

필요 시 style로 override:

{
    tagName: 'stickyDiv',
    position: 'top',
    style: { top: '0' }  // 3rem 대신 화면 최상단 붙임
}

이벤트

이벤트발생 시점콜백 인자

click 클릭 시 (sender, element, evt)
contextmenu 우클릭 시 (sender, element, evt)

stopPropagation: true이면 이벤트 버블링 차단.

메서드

Va.Component 공통 메서드.

내부 구조

<div class="va-div sticky top" tag-name="stickyDiv">
    <!-- 자식 컴포넌트 또는 innerHTML -->
</div>

position 값에 따라 sticky top/sticky bottom 등 클래스 추가.

사용 시점 — 언제 쓰나

  • 긴 폼의 하단 저장 버튼 — 스크롤해도 항상 보이는 저장/취소 바
  • 긴 리스트/문서의 상단 필터 — 스크롤해도 검색 조건 계속 노출
  • 사이드 목차 (TOC) — 문서 옆에 붙어 스크롤 따라오는 목차
  • 테이블 헤더 고정 — 그리드가 아닌 일반 HTML 테이블일 때 헤더 sticky
  • 알림/공지 배너 — 화면 상단 공지가 스크롤해도 유지

사용하지 말아야 할 때

  • 항상 화면에 완전 고정 (스크롤 밖으로도 안 사라짐) → CSS position: fixed 직접 사용
  • 드래그 가능한 창  Va.Dialog 
  • 팝업/드롭다운 → 각각 전용 컴포넌트
  • 그리드 헤더 고정  Va.Grid가 자체 처리

자주 쓰는 조합 예시

긴 폼의 하단 액션 바 고정

{
    tagName: 'page',
    tags: [{
        tagName: 'section',
        style: { minHeight: '2000px' },
        tags: [ /* 긴 폼 필드들 */ ]
    },{
        tagName: 'stickyDiv',
        position: 'bottom',
        style: {
            bottom: '0',
            background: 'var(--colorBackground)',
            padding: '15px',
            borderTop: '1px solid var(--colorNeutralStroke)',
            display: 'flex',
            gap: '10px',
            justifyContent: 'flex-end'
        },
        tags: [
            { tagName: 'button', text: '취소' },
            { tagName: 'button', text: '저장', appearance: 'primary' }
        ]
    }]
}

상단 검색 필터 고정

{
    tagName: 'page',
    tags: [{
        tagName: 'stickyDiv',
        position: 'top',
        style: {
            top: '0',
            background: 'var(--colorBackground)',
            padding: '10px',
            borderBottom: '1px solid var(--colorNeutralStroke)',
            zIndex: 10
        },
        tags: [
            { tagName: 'inputField', label: '검색' },
            { tagName: 'button', text: '조회', appearance: 'primary' }
        ]
    },{
        tagName: 'section',
        tags: [ /* 긴 결과 리스트 */ ]
    }]
}

문서 옆 목차 (좌측 사이드)

{
    tagName: 'page',
    layout: 'ds-flex fd-row gap-m',
    tags: [{
        tagName: 'stickyDiv',
        position: 'left',
        style: {
            top: '20px',
            width: '200px',
            alignSelf: 'flex-start'
        },
        tags: [
            { tagName: 'nav', tags: [
                { tagName: 'a', innerHTML: '1. 개요', attributes: { href: '#overview' } },
                { tagName: 'a', innerHTML: '2. 설치', attributes: { href: '#install' } },
                { tagName: 'a', innerHTML: '3. 사용법', attributes: { href: '#usage' } }
            ]}
        ]
    },{
        tagName: 'section',
        style: { flex: 1 },
        tags: [ /* 긴 문서 본문 */ ]
    }]
}

공지 배너 (닫기 가능)

{
    tagName: 'stickyDiv',
    position: 'top',
    stopPropagation: true,
    style: {
        top: '0',
        background: 'var(--colorPrimary)',
        color: 'white',
        padding: '10px 20px',
        display: 'flex',
        alignItems: 'center',
        gap: '10px',
        zIndex: 100
    },
    tags: [
        { tagName: 'div', innerHTML: '🎉 신규 버전 v2.0 출시!', style: { flex: 1 } },
        { tagName: 'button', text: '자세히', appearance: 'transparent' }
    ]
}

실전 예시 — 긴 CRUD 화면

config(){
    return {
        tagName: 'page',
        tags: [{
            tagName: 'stickyDiv',
            position: 'top',
            style: {
                top: '0',
                background: 'var(--colorBackground)',
                padding: '10px',
                borderBottom: '1px solid var(--colorNeutralStroke)',
                zIndex: 10
            },
            tags: [{
                tagName: 'titleBar',
                tags: [
                    { tagName: 'title', innerHTML: '주문 상세' },
                    { tagName: 'div', style: { flex: 1 } },
                    { tagName: 'button', text: '취소' },
                    { tagName: 'button', text: '저장', appearance: 'primary' }
                ]
            }]
        },{
            tagName: 'section',
            tags: [ /* 긴 폼 필드들 (수백 개) */ ]
        }]
    };
}

주의사항

  • 부모 컨테이너에 overflow: hidden 있으면 sticky 작동 안 함 — 이건 CSS 스펙상 제약 (VanillaFront 문제 아님)
  • 부모가 스크롤 가능해야 sticky가 의미 있음 — 스크롤 없으면 그냥 일반 요소처럼 보임
  • 부모의 스크롤 영역을 벗어나면 sticky 종료 — 부모 컨테이너 밖으로 밀려나가면 함께 스크롤됨
  • 기본 offset 3rem — 화면 최상단에 붙이고 싶으면 style: { top: '0' } override 필수
  • z-index 명시 권장 — 다른 컴포넌트와 겹칠 때 위에 표시되도록 zIndex: 10 이상 지정
  • 자식이 없으면 안 보임 — 배경/테두리 없으면 투명 → 배경색 명시 필요
  • Va.Div 아닌 Va.Component 상속 — Div의 gridHeader/gridBody 같은 속성은 없음

대안 비교

상황추천

스크롤 시 부모 안에서 고정 Va.StickyDiv
화면 절대 고정 (스크롤 무관) 일반 Va.Div + style: { position: 'fixed' }
모달 창 Va.Dialog
툴팁 Va.Tooltip
드롭다운 메뉴 Va.Menu / Va.ContextMenu
그리드 헤더 고정 Va.Grid (자체 처리)
순수 그루핑 Va.Div

참고

'컴포넌트 > 패널 외 영역 (Div, Span)' 카테고리의 다른 글

GridDiv (그리드 디비전)  (0) 2026.09.18
SearchPanel (조회패널)  (0) 2026.09.18
TitleBar (타이틀바)  (0) 2026.09.18
SubTitle (서브타이틀)  (0) 2026.09.18
Title (타이틀)  (0) 2026.09.18