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 |
참고
- API 문서 페이지: https://vanillafront.com/docs.html?theme=light#main#apistickydiv
- 연관: Va.Component(부모), 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 |