class:active={isActive} — 이 한 줄이 React에서 classnames 라이브러리로 해결하던 것을 대체합니다.

개념 정의

조건부 스타일링 은 상태에 따라 요소의 스타일을 동적으로 변경하는 패턴입니다. Svelte는 class: 디렉티브, 동적 style 속성, CSS 변수 등 여러 가지 방법을 기본 제공합니다.

class: 디렉티브

SVELTE
<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 속성

SVELTE
<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: 디렉티브

SVELTE
<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)

SVELTE
<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 변수 전달

SVELTE
<!-- 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>
SVELTE
<!-- 사용 — CSS 변수를 props처럼 전달 -->
<Box --bg="#1a1a2e" --color="white" --padding="2rem">
  <p>다크 박스</p>
</Box>

<Box --bg="#e8f5e9" --color="#2e7d32">
  <p>그린 박스</p>
</Box>

실전 패턴 — 테마 토글

SVELTE
<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의 강점입니다.

댓글 로딩 중...