웹 애플리케이션을 개발하다 보면 상단은 가변적인 높이를, 하단은 고정된 높이를 가져야 하는 레이아웃을 자주 마주치게 됩니다. 대표적으로 채팅 애플리케이션의 메시지 영역과 입력창, 또는 긴 콘텐츠 영역과 고정 푸터가 있는 대시보드 등이 이러한 패턴을 사용합니다. 오늘은 flexShrink 속성을 활용해 이러한 레이아웃을 효과적으로 구현하는 방법을 알아보겠습니다.
<Box sx={{
display: 'flex',
flexDirection: 'column',
height: '100vh',
'& > .content-area': {
flex: 1,
minHeight: 0, // 중요: 컨텐츠 오버플로우 시 필수
overflow: 'auto'
},
'& > .fixed-area': {
height: '80px',
flexShrink: 0 // 핵심: 고정 높이 유지
}
}}>
<div className="content-area">스크롤 가능한 콘텐츠</div>
<div className="fixed-area">고정 높이 영역</div>
</Box>
height: 100vh: 뷰포트 전체 높이를 사용하여 레이아웃의 기본 틀 형성display: flex: Flexbox 레이아웃 활성화flexDirection: column: 자식 요소들을 세로 방향으로 배치flex: 1: 남은 공간을 모두 차지하도록 설정minHeight: 0: 컨텐츠가 넘칠 때 컨테이너가 축소될 수 있도록 허용overflow: auto: 내용이 넘칠 경우 스크롤바 표시height: 80px: 고정된 높이 값 설정flexShrink: 0: 핵심 속성 - 뷰포트가 축소되어도 설정된 높이를 유지flexShrink는 Flex 아이템이 컨테이너 내에서 축소되는 비율을 지정하는 속성입니다. 기본값은 1로, 이는 필요한 경우 아이템이 축소될 수 있음을 의미합니다. 0으로 설정하면 해당 아이템은 절대 축소되지 않습니다.
/* 축소 가능 (기본값) */
flex-shrink: 1;
/* 축소 불가능 - 고정 크기 유지 */
flex-shrink: 0;
채팅 애플리케이션
<ChatContainer>
<MessageList /> {/* flex: 1, minHeight: 0 */}
<InputArea /> {/* flexShrink: 0, height: 60px */}
</ChatContainer>
대시보드 레이아웃
<DashboardLayout>
<MainContent /> {/* flex: 1, minHeight: 0 */}
<FixedFooter /> {/* flexShrink: 0, height: 80px */}
</DashboardLayout>
컨텐츠 영역에서 minHeight: 0을 설정하지 않으면, 내용이 많을 때 예상치 못한 오버플로우가 발생할 수 있습니다. 이는 flex 아이템의 기본 최소 크기 때문입니다.
<Box sx={{
'& > .fixed-area': {
height: { xs: '60px', md: '80px' }, // 반응형 높이 조정
flexShrink: 0
}
}}>
여러 레벨의 Flex 컨테이너가 중첩된 경우, 각 레벨에서 적절한 flexShrink 값을 설정해야 합니다.
<OuterContainer>
<InnerContainer sx={{ flexShrink: 0 }}>
<FixedHeightContent />
</InnerContainer>
</OuterContainer>
리플로우 최소화
will-change 속성 활용
.fixed-area {
will-change: height;
transition: height 0.3s ease;
}
flexShrink는 단순해 보이지만, 적재적소에 활용하면 복잡한 레이아웃 문제를 우아하게 해결할 수 있는 강력한 도구입니다. 특히 고정 높이와 가변 높이가 공존하는 현대적인 웹 애플리케이션에서는 필수적인 속성이라고 할 수 있습니다.
이 글에서 다룬 패턴을 기본으로 하되, 각자의 프로젝트 요구사항에 맞게 응용하시면 더욱 견고한 레이아웃을 구현하실 수 있을 것입니다.