조건부 스타일링 — class: 디렉티브와 동적 스타일 패턴
class:active={isActive}— 이 한 줄이 React에서 classnames 라이브러리로 해결하던 것을 대체합니다.
개념 정의
조건부 스타일링 은 상태에 따라 요소의 스타일을 동적으로 변경하는 패턴입니다. Svelte는 class: 디렉티브, 동적 style 속성, CSS 변수 등 여러 가지 방법을 기본 제공합니다.
class: 디렉티브
<script>
let isActive = $state(false);
let isDisabled = $state(false);
let hasError = $state(false);
</script>
<!-- class:클래스명={조건} -->
<button
class:active={isActive}
class:disabled={isDisabled}
onclick={() => isActive = !isActive}
>
{isActive ? '활성' : '비활성'}
</button>
<!-- 변수명과 클래스명이 같으면 단축 표기 -->
<div class:hasError>
{hasError ? '오류 있음' : '정상'}
</div>
<style>
.active { background: #ff3e00; color: white; }
.disabled { opacity: 0.5; pointer-events: none; }
.hasError { border: 2px solid red; }
</style>
동적 class 속성
<script>
let variant = $state('primary');
let size = $state('md');
</script>
<!-- 템플릿 리터럴로 동적 클래스 -->
<button class="btn btn-{variant} btn-{size}">
버튼
</button>
<!-- 삼항 연산자 -->
<div class={isActive ? 'card active' : 'card'}>
카드 컨텐츠
</div>
<!-- 여러 조건 조합 -->
<div class={[
'card',
isActive && 'active',
isDisabled && 'disabled',
hasError && 'error'
].filter(Boolean).join(' ')}>
복합 스타일
</div>
<style>
.btn { padding: 0.5rem 1rem; border: none; border-radius: 4px; }
.btn-primary { background: #007bff; color: white; }
.btn-secondary { background: #6c757d; color: white; }
.btn-sm { font-size: 0.8rem; }
.btn-md { font-size: 1rem; }
.btn-lg { font-size: 1.2rem; }
</style>
style: 디렉티브
<script>
let color = $state('#ff3e00');
let fontSize = $state(16);
let opacity = $state(1);
</script>
<!-- style:속성={값} -->
<p
style:color
style:font-size="{fontSize}px"
style:opacity
>
동적 스타일이 적용된 텍스트
</p>
<!-- 조건부 스타일 -->
<div style:display={isVisible ? 'block' : 'none'}>
조건부로 보이는 요소
</div>
<input type="color" bind:value={color} />
<input type="range" bind:value={fontSize} min="12" max="48" />
<input type="range" bind:value={opacity} min="0" max="1" step="0.1" />
CSS 변수 (Custom Properties)
<script>
let theme = $state({
primary: '#ff3e00',
secondary: '#676778',
radius: '8px',
});
</script>
<!-- CSS 변수를 컴포넌트에 전달 -->
<div
style:--primary={theme.primary}
style:--secondary={theme.secondary}
style:--radius={theme.radius}
class="themed-card"
>
<h3>테마 카드</h3>
<p>CSS 변수로 테마 적용</p>
<button>버튼</button>
</div>
<style>
.themed-card {
border: 2px solid var(--primary);
border-radius: var(--radius);
padding: 1rem;
}
.themed-card button {
background: var(--primary);
color: white;
border: none;
border-radius: var(--radius);
padding: 0.5rem 1rem;
}
</style>
컴포넌트에 CSS 변수 전달
<!-- Box.svelte -->
<div class="box">
<slot />
</div>
<style>
.box {
background: var(--bg, #f0f0f0);
color: var(--color, #333);
padding: var(--padding, 1rem);
border-radius: var(--radius, 4px);
}
</style>
<!-- 사용 — CSS 변수를 props처럼 전달 -->
<Box --bg="#1a1a2e" --color="white" --padding="2rem">
<p>다크 박스</p>
</Box>
<Box --bg="#e8f5e9" --color="#2e7d32">
<p>그린 박스</p>
</Box>
실전 패턴 — 테마 토글
<script>
let isDark = $state(false);
let theme = $derived(isDark ? {
bg: '#1a1a2e',
text: '#eee',
primary: '#e94560',
card: '#16213e',
} : {
bg: '#ffffff',
text: '#333',
primary: '#ff3e00',
card: '#f5f5f5',
});
</script>
<div
class="app"
class:dark={isDark}
style:--bg={theme.bg}
style:--text={theme.text}
style:--primary={theme.primary}
style:--card={theme.card}
>
<button onclick={() => isDark = !isDark}>
{isDark ? '라이트 모드' : '다크 모드'}
</button>
<div class="card">
<h2>테마 전환 데모</h2>
<p>CSS 변수로 깔끔하게 구현합니다.</p>
</div>
</div>
<style>
.app {
background: var(--bg);
color: var(--text);
min-height: 100vh;
padding: 2rem;
transition: all 0.3s;
}
.card {
background: var(--card);
padding: 1.5rem;
border-radius: 8px;
margin-top: 1rem;
}
button {
background: var(--primary);
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
}
</style>
면접 포인트
- "class: 디렉티브와 일반 class 속성의 차이는?":
class:디렉티브는 특정 클래스의 추가/제거를 조건부로 제어합니다. 기존 class 속성과 ** 함께 사용 가능 **하며, 컴파일러가 최적화된 DOM 업데이트 코드를 생성합니다. - "CSS 변수를 컴포넌트 API로 쓰는 장점은?": Props로 스타일을 전달하는 것보다 CSS 계층 구조를 활용할 수 있고, 자식 컴포넌트의 내부 구현을 몰라도 스타일을 커스터마이징할 수 있습니다.
정리
Svelte의 조건부 스타일링은 class:, style:, CSS 변수 세 가지를 조합하면 거의 모든 시나리오를 커버합니다. 외부 라이브러리 없이도 깔끔한 동적 스타일링이 가능하다는 것이 Svelte의 강점입니다.
댓글 로딩 중...