Files
2nd/10_Wiki/Topics/Coding/Frontend_SVG_Patterns.md
T
2026-05-09 22:47:42 +09:00

8.4 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
frontend-svg-patterns SVG — Scaling / Animation / Sprite / React Coding draft B conceptual 2026-05-09 2026-05-09
frontend
svg
vector
vibe-coding
language applicable_to
SVG / CSS / TS
Frontend
SVG
vector graphics
SVG sprite
viewBox
lucide-react
animation

SVG Patterns

Vector graphics. Scalable, small, scriptable, themeable. Icon / illustration / chart / animation. PNG 보다 거의 항상 좋음 (단순 graphic).

📖 핵심 개념

  • viewBox: coordinate system.
  • preserveAspectRatio: scaling.
  • currentColor: 부모 색 따름.
  • Sprite: 여러 icon 한 file.

💻 코드 패턴

기본 SVG

<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="40" fill="hotpink" />
  <text x="50" y="55" text-anchor="middle" fill="white">Hi</text>
</svg>

viewBox 가 핵심

<!-- 항상 viewBox 사용 -->
<svg viewBox="0 0 24 24">
  <!-- 0,0 부터 24x24 coordinate -->
</svg>

<!-- width / height 안 — CSS 로 -->
<svg viewBox="0 0 24 24" style="width: 24px; height: 24px;">

→ Scalable. CSS 로 size 제어.

currentColor (theme 친화)

<svg viewBox="0 0 24 24" fill="currentColor">
  <path d="M5 13l4 4L19 7" />
</svg>
.icon { color: blue; }  /* SVG fill 도 blue */
.icon:hover { color: red; }  /* 자동 hover */

→ 부모 color 따름. Theme / dark mode 자동.

Inline SVG (modern)

function CheckIcon() {
  return (
    <svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor">
      <path d="M5 13l4 4L19 7" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

lucide-react (icon library)

yarn add lucide-react
import { Heart, Home, Settings, ChevronRight } from 'lucide-react';

<Heart size={24} className="text-red-500" />
<Home className="size-6 text-gray-600" />

→ Tree-shakable. 큰 set.

Icon system (자체)

// icons/index.ts
export { default as CheckIcon } from './check.svg';
export { default as CloseIcon } from './close.svg';
// ...

// 사용
import { CheckIcon } from '@/icons';
<CheckIcon className="size-4" />
// vite.config.ts — SVG → React
import svgr from 'vite-plugin-svgr';
plugins: [svgr()];

→ SVG file → React component 자동.

SVG sprite (1 fetch, 많은 icon)

<!-- icons.svg -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
  <symbol id="check" viewBox="0 0 24 24">
    <path d="M5 13l4 4L19 7" />
  </symbol>
  <symbol id="close" viewBox="0 0 24 24">
    <path d="M6 6L18 18M6 18L18 6" />
  </symbol>
</svg>

<!-- Use -->
<svg width="24" height="24"><use href="/icons.svg#check" /></svg>

→ 한 fetch — cache. 100 icon 도 OK.

Stroke-based icon

<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10" />
  <line x1="12" y1="8" x2="12" y2="12" />
  <circle cx="12" cy="16" r="0.5" fill="currentColor" />
</svg>

→ Lucide / Tabler / Phosphor 의 style.

Filled icon

<svg viewBox="0 0 24 24" fill="currentColor">
  <path d="M12 21l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.18L12 21z" />
</svg>

→ Solid icon (Material).

CSS animation

<svg viewBox="0 0 24 24">
  <circle class="loader" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" />
</svg>
.loader {
  stroke-dasharray: 60;
  stroke-dashoffset: 0;
  animation: loading 1s linear infinite;
}

@keyframes loading {
  to { stroke-dashoffset: 60; }
}

→ SVG path = stroke-dash.

SMIL animation (built-in)

<svg viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="40" fill="red">
    <animate attributeName="r" from="40" to="50" dur="1s" repeatCount="indefinite" />
  </circle>
</svg>

→ JS 없이 animation. Browser 지원 OK.

Path morphing (SVGator / GSAP / Lottie)

// Path A → Path B
gsap.to('#shape', {
  attr: { d: 'M10,10 L90,90' },
  duration: 1,
});

Logo / illustration

Vector design tools:
- Figma → SVG export
- Illustrator
- Inkscape (OSS)

→ Path / shape 직접 export.

Optimization

# SVGO
npx svgo input.svg
npx svgo *.svg

# 또는 SVGOMG (web)

→ 50% 작아지는 보통 — comments / metadata 제거.

React + SVG

// Inline (small icons)
<svg viewBox="0 0 24 24"><path d="..." /></svg>

// React component (vite-plugin-svgr)
import Icon from './icon.svg?react';
<Icon className="size-4" />

// img tag (큰 / 변동 X)
<img src="/logo.svg" alt="Logo" />

// 또는 url
import logoUrl from './logo.svg';
<img src={logoUrl} alt="Logo" />

→ Inline = themeable. img = cacheable.

Charts (SVG-based)

// d3 / visx — SVG 직접
const path = d3.line()(data.map(d => [d.x, d.y]));
return <path d={path} stroke="blue" fill="none" />;

→ SVG = chart 의 자연.

Patterns / gradients

<svg viewBox="0 0 200 100">
  <defs>
    <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" stop-color="red" />
      <stop offset="100%" stop-color="blue" />
    </linearGradient>
    
    <pattern id="dots" width="10" height="10" patternUnits="userSpaceOnUse">
      <circle cx="5" cy="5" r="2" fill="black" />
    </pattern>
  </defs>
  
  <rect width="200" height="50" fill="url(#grad)" />
  <rect y="50" width="200" height="50" fill="url(#dots)" />
</svg>

Filters

<svg>
  <defs>
    <filter id="blur">
      <feGaussianBlur stdDeviation="3" />
    </filter>
    
    <filter id="shadow">
      <feDropShadow dx="2" dy="2" stdDeviation="3" />
    </filter>
  </defs>
  
  <text filter="url(#shadow)">Shadow</text>
</svg>

A11y

<svg role="img" aria-labelledby="title">
  <title id="title">Heart icon</title>
  <path d="..." />
</svg>

<!-- 또는 decorative -->
<svg aria-hidden="true">...</svg>

→ Screen reader 친화.

1-line / Tailwind utility

<svg class="size-6 text-red-500">...</svg>

→ Tailwind 가 SVG 자연.

MathML / chart 기타

SVG: 자유 형식 vector.
Canvas: pixel — 큰 rendering.
WebGL: 3D / GPU.

→ Static / scalable / theme-friendly = SVG.

Use cases

- Icon (Lucide / Heroicons)
- Logo
- Chart (D3 / Visx)
- Illustration
- Loading spinner
- Diagram (Mermaid / draw.io)
- Map / floor plan

Bundle size

Inline SVG icon:    ~500 bytes
PNG @1x / @2x / @3x: 5-50 KB

→ Icon = SVG 거의 항상.

Generate at build

// 자동 component generation
import { generateSvgComponents } from 'svg-to-jsx';
generateSvgComponents('./icons/', './src/components/icons/');

Optimization (icon font 보다)

Icon font:
+ 1 file load
- A11y 약함
- Fixed color 어려움
- CSS 만 styling

SVG sprite / inline:
+ A11y OK
+ 색 / size 자유
+ Animation 가능
+ Better fallback

→ 2024+ = SVG 가 더 좋음.

Common 사이즈

size-4 (16px): inline text icon
size-5 (20px): button icon
size-6 (24px): main icon
size-8 (32px): large
size-12 (48px): hero

Colored icons (multi-color)

<svg viewBox="0 0 24 24">
  <path d="..." fill="red" />
  <path d="..." fill="blue" />
</svg>

→ Theme 어려움. CSS variable 사용:

<svg viewBox="0 0 24 24" style="--primary: red; --secondary: blue;">
  <path d="..." fill="var(--primary)" />
  <path d="..." fill="var(--secondary)" />
</svg>

🤔 의사결정 기준

사용 추천
Icon system Lucide / 자체 SVG sprite
Logo Inline SVG
Chart SVG (D3 / Visx)
Illustration SVG
Photo PNG / WebP / AVIF
3D WebGL / Three.js

안티패턴

  • viewBox 없음: 안 scale.
  • Hard-coded color: theme X. currentColor.
  • PNG icon (multi-resolution): 매 size 별 file. SVG 하나면.
  • Inline SVG 큰 (100+ path): HTML bloat. external file.
  • No optimization (raw export): 50% 큰.
  • A11y 무시: title / aria-label.

🤖 LLM 활용 힌트

  • viewBox + currentColor + sprite.
  • Lucide / Heroicons / Tabler 가 modern.
  • SVGO 자동 optimize.
  • vite-plugin-svgr = React component.

🔗 관련 문서