StackPanel은 WPF와 Avalonia에서 자주 쓰는 단방향 레이아웃 컨테이너다. 이 글에서는 동일한 시각적 결과를 HTML과 CSS로 재현하는 방법을 살펴본다. 프레임워크에 구애받지 않고 순수한 마크업과 스타일로 접근하며, 예시 코드는 Vue 문법을 기반으로 작성했다.
기본 세로 쌓기
아래 XAML은 여러 TextBlock을 위에서부터 쌓는 구조다.
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Item Alpha"/>
<TextBlock Text="Item Beta"/>
<TextBlock Text="Item Gamma"/>
<TextBlock Text="Item Delta"/>
<TextBlock Text="Item Epsilon"/>
<TextBlock Text="Item Zeta"/>
</StackPanel>
HTML에서는 블록 요소의 기본 흐름을 활용한다. 별도의 Flex나 Grid 없이도 자연스럽게 세로로 배치된다.
<div class="v-container">
<p class="v-item">Item Alpha</p>
<p class="v-item">Item Beta</p>
<p class="v-item">Item Gamma</p>
<p class="v-item">Item Delta</p>
<p class="v-item">Item Epsilon</p>
<p class="v-item">Item Zeta</p>
</div>
.v-container {
width: fit-content;
margin-inline: auto;
}
.v-item {
display: block;
}
세로 배치 속 개별 수평 정렬
StackPanel 너비가 고정되어 있을 때, 자식 요소마다 HorizontalAlignment를 다르게 줄 수 있다. 예를 들어 첫 번째는 왼쪽, 두 번째는 가운데, 세 번째는 오른쪽 붙이기다.
<StackPanel Width="200" Background="Aqua">
<TextBlock HorizontalAlignment="Left" Text="Left"/>
<TextBlock HorizontalAlignment="Center" Text="Center"/>
<TextBlock HorizontalAlignment="Right" Text="Right"/>
<TextBlock Text="Default"/>
<TextBlock Text="Default"/>
<TextBlock Text="Default"/>
</StackPanel>
CSS에서는 justify-self를 활용해 동일한 효과를 낼 수 있다. 단, justify-self가 블록 레벨 요소에서 제대로 작동하려면 부모가 Grid나 Flex 컨테이너여야 하므로, 여기서는 부모를 Flex 컬럼으로 전환한다.
<div class="v-container-align">
<span class="v-item-align to-start">Left</span>
<span class="v-item-align to-center">Center</span>
<span class="v-item-align to-end">Right</span>
<span class="v-item-align">Default</span>
<span class="v-item-align">Default</span>
<span class="v-item-align">Default</span>
</div>
.v-container-align {
display: flex;
flex-direction: column;
width: 200px;
background: aqua;
}
.v-item-align {
display: block;
}
.to-start { justify-self: self-start; }
.to-center { justify-self: center; }
.to-end { justify-self: self-end; }
수평 방향 전환
Orientation="Horizontal" 속성을 주면 자식 요소가 가로로 펼쳐진다.
<StackPanel Orientation="Horizontal">
<TextBlock Text="Alpha"/>
<TextBlock Text="Beta"/>
<TextBlock Text="Gamma"/>
<TextBlock Text="Delta"/>
<TextBlock Text="Epsilon"/>
<TextBlock Text="Zeta"/>
</StackPanel>
CSS에서는 Flexbox의 기본 방향(행 방향)을 그대로 이용하면 된다. 자식은 inline-block으로 두어 텍스트 흐름 속성을 유지한다.
<div class="h-container">
<span class="h-item">Alpha</span>
<span class="h-item">Beta</span>
<span class="h-item">Gamma</span>
<span class="h-item">Delta</span>
<span class="h-item">Epsilon</span>
<span class="h-item">Zeta</span>
</div>
.h-container {
display: flex;
}
.h-item {
display: inline-block;
}
가로 배치 속 개별 수직 정렬
수평 StackPanel 내에서 특정 자식만 위아래 위치를 다르게 주는 경우, VerticalAlignment 속성을 사용한다.
<StackPanel Height="150" Background="Aqua" Orientation="Horizontal">
<TextBlock VerticalAlignment="Top" Text="Top"/>
<TextBlock VerticalAlignment="Center" Text="Center"/>
<TextBlock VerticalAlignment="Bottom" Text="Bottom"/>
<TextBlock Text="Default"/>
<TextBlock Text="Default"/>
<TextBlock Text="Default"/>
</StackPanel>
CSS의 align-self로 교차축 정렬을 개별 제어한다.
<div class="h-container-align">
<span class="h-item-align pin-top">Top</span>
<span class="h-item-align pin-middle">Center</span>
<span class="h-item-align pin-bottom">Bottom</span>
<span class="h-item-align">Default</span>
<span class="h-item-align">Default</span>
<span class="h-item-align">Default</span>
</div>
.h-container-align {
display: flex;
background: aqua;
height: 150px;
}
.h-item-align {
display: inline-block;
}
.pin-top { align-self: flex-start; }
.pin-middle { align-self: center; }
.pin-bottom { align-self: flex-end; }
요소 간 간격: Spacing 대신 gap
Avalonia 11부터 StackPanel에 Spacing 속성이 추가되었다. HTML/CSS에서는 이미 널리 지원되는 gap 속성으로 같은 결과를 낼 수 있다.
<div class="spaced-row">
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
</div>
.spaced-row {
display: flex;
gap: 12px;
}
.card {
width: 80px;
height: 80px;
background: #7fb3d5;
}
gap은 행과 열 간격을 각각 지정할 수도 있다. gap: 10px 20px;처럼 작성하면 세로 10px, 가로 20px이 적용된다.
속성 대응표
| WPF / Avalonia | HTML / CSS | 설명 |
|---|---|---|
| Orientation="Vertical" | display: flex; flex-direction: column; |
세로 쌓기, gap으로 간격 관리 권장 |
| Orientation="Horizontal" | display: flex; |
기본 행 방향 |
| HorizontalAlignment="Left" | justify-self: self-start |
수평 쪽 정렬 |
| HorizontalAlignment="Center" | justify-self: center |
수평 가운데 정렬 |
| HorizontalAlignment="Right" | justify-self: self-end |
수평 오른쪽 정렬 |
| VerticalAlignment="Top" | align-self: flex-start |
수직 상단 정렬 |
| VerticalAlignment="Center" | align-self: center |
수직 가운 정렬 |
| VerticalAlignment="Bottom" | align-self: flex-end |
수직 하단 정렬 |
| Spacing | gap |
자식 요소 사이 간격 |