본문으로 건너뛰기
yutils

SVG 최적화 — 편집 도구 50KB export 를 5KB 까지 줄이기

편집 도구 export 가 왜 부풀어 오르는지, SVGO 가 무엇을 제거하는지, inline vs 외부 참조, sprite 시트, 사용자 업로드 SVG 보안 체크리스트.

약 7분 읽기

Figma·Illustrator 에서 SVG 를 export 하면 보통 40-80 KB. 같은 그래픽 이 SVGO 한 번이면 5-10 KB. 차이의 거의 전부가 편집 도구의 메타데이터 다. 이 가이드는 편집 도구가 SVG 에 무엇을 박는지, 제거해도 안전한 것은 무엇인지, inline vs 외부 참조 선택, sprite 시트, 사용자 업로드 SVG 의 XSS 방어를 정리한다.

편집 도구가 박는 군더더기

전형적인 Figma export:

<svg width="24" height="24" viewBox="0 0 24 24" fill="none"
     xmlns="http://www.w3.org/2000/svg">
  <!-- Generator: figma -->
  <metadata>
    <rdf:RDF xmlns:rdf="...">...</rdf:RDF>
  </metadata>
  <defs>
    <clipPath id="clip0_1_2">
      <rect width="24" height="24" fill="white" transform="translate(0)" />
    </clipPath>
  </defs>
  <g clip-path="url(#clip0_1_2)">
    <path d="M12 2C6.48..." fill="#0F172A" />
  </g>
</svg>

제거 가능:

  • <metadata>, <sodipodi:*>, <inkscape:*> — 편집 도구 전용 네임스페이스.
  • XML 주석.
  • 기본값 attribute — fill="none", stroke-linecap="butt" 등.
  • <defs>, 빈 <g>.
  • 쓰이지 않는 clipPath, mask, filter.
  • path data 의 과한 정밀도 — d="M 12.0000001 2.0000003" M 12 2.
  • id="clip0_1_2" 같은 무의미한 자동 id.
  • XML 선언 (<?xml ... ?>) — HTML 안 inline 할 때 불필요.

SVGO 한 줄 명령

npm i -D svgo
npx svgo icon.svg -o icon.optimized.svg

# 폴더 일괄
npx svgo -f icons/ -o icons-min/

# config 파일 (svgo.config.js)
module.exports = {
  multipass: true,
  plugins: [
    "preset-default",
    {name: "removeViewBox", active: false},  // viewBox 보존 (반응형 필수)
    {name: "removeDimensions", active: true}, // width/height 제거 → CSS 자유
  ],
};

브라우저에서 시각 확인하려면 SVGOMG (https://jakearchibald.github.io/svgomg/) — slider 로 각 옵션 영향 즉시 비교.

viewBox 유지, width/height 제거

편집 도구 export 는 보통 width="24" height="24" viewBox="0 0 24 24". 세 가지 모두 동일 정보. viewBox 만 두면 SVG 가 크기 무관 벡터 가 되어 CSS 로 자유롭게 resize.

<!-- 권장 -->
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
  <path d="..." />
</svg>

<!-- CSS -->
.icon { width: 24px; height: 24px; }
.icon-large { width: 48px; height: 48px; }

inline vs 외부 참조

Inline SVG — 권장 (작은 아이콘)

<button>
  <svg viewBox="0 0 24 24" aria-hidden="true">
    <path d="..." />
  </svg>
  복사
</button>
  • 장점: HTTP 요청 0. CSS 로 currentColor 색 변경 자동. JS 로 한 path 만 변경 가능.
  • 단점: 같은 아이콘 N 번 = HTML bytes N 번. gzip 이 잘 압축하지만 N=수십+면 의미.

외부 SVG — 큰 일러스트레이션

<img src="/hero.svg" alt="..." width="800" height="400" />
<!-- 또는 -->
<object data="/diagram.svg" type="image/svg+xml"></object>
  • 장점: 브라우저 캐시. 한 번 다운로드 → 사이트 전역 재사용.
  • 단점: img 안 SVG 는 CSS / JS 로 내부 조작 X.

Data URI inline

SVG 를 base64 또는 URL-encoded data URI 로 inline. CSS background 안 주로 사용.

background-image: url("data:image/svg+xml,%3Csvg ... %3E");

이미지 → Base64 (Data URI) 가 SVG 도 데이터 URI 로 변환. 단 SVG 는 base64 보다 URL-encoded 가 ~30% 작아 권장.

Sprite 시트 — 많은 아이콘

20+ 아이콘이 있고 inline 이 부담스러울 때. 모든 아이콘을 한 SVG 의 <symbol> 로 정의 → <use> 로 참조.

<!-- sprite.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="i-search" viewBox="0 0 24 24">
    <path d="..." />
  </symbol>
  <symbol id="i-trash" viewBox="0 0 24 24">
    <path d="..." />
  </symbol>
</svg>

<!-- 사용 -->
<svg class="icon"><use href="/sprite.svg#i-search" /></svg>
<svg class="icon"><use href="/sprite.svg#i-trash" /></svg>

브라우저는 sprite.svg 를 한 번만 받음. fill: currentColor 로 색상 컨트롤. 외부 sprite cross-origin 일 때 CORS 필요.

색상·테마 — currentColor

하드코딩한 색을 currentColor 로 바꾸면 CSS color 속성으로 자동 추종.

<!-- before -->
<svg viewBox="0 0 24 24"><path d="..." fill="#0F172A" /></svg>

<!-- after -->
<svg viewBox="0 0 24 24"><path d="..." fill="currentColor" /></svg>

/* CSS */
.icon { color: var(--fg); }
.icon:hover { color: var(--accent); }
[data-mode="dark"] .icon { color: var(--fg-dark); }

다크 모드·테마 시스템과 자연 어울림. lucide-react·heroicons 등 라이브 러리가 다 사용하는 패턴.

사용자 업로드 SVG — XSS 방어

SVG 는 HTML / JS 를 포함할 수 있는 위험 포맷. 사용자 업로드를 그대로 렌더하면 XSS.

<!-- 악의적 SVG 예 -->
<svg xmlns="http://www.w3.org/2000/svg">
  <script>alert(1)</script>
  <a href="javascript:alert(1)"><text>click</text></a>
  <image href="x" onerror="alert(1)" />
</svg>

방어책:

  1. inline 금지<img src="upload.svg"> 으로 표시. <img> 안 SVG 는 script 가 동작 X.
  2. inline 이 꼭 필요하면 DOMPurify 같은 sanitizer (server 또는 client).
  3. uploaded SVG 는 별도 도메인 (예: uploads.example.com) 에서 서빙 — cookie 도메인 분리.
  4. CSP script-src 'self' + object-src 'none' 으로 fallback 방어.

아이콘 라이브러리 vs 직접

2026 년 표준 선택지:

  • lucide-react — open source, tree-shake, 1500+ 아이콘. 가장 흔한 선택. 도구 당 ~1 KB.
  • heroicons — Tailwind 팀. 200+ 아이콘. outline/solid 변형.
  • radix-icons — 무게감 일관, 디자인 시스템 친화.
  • tabler-icons — 4500+ 무료.

직접 만들 때는 viewBox 24×24 또는 16×16 통일, stroke width 일관 (1.5 또는 2), rounded join 통일. 디자인 시스템에 박힐 때 시각 일관성 ↑.

흔한 함정

1. removeViewBox 실수

SVGO 의 preset-default 가 기본으로 viewBox 제거. 반응형 SVG 깨짐. 항상 removeViewBox: false.

2. 정밀도 손실

SVGO 기본 정밀도 3. 아이콘에는 충분, 정밀 일러스트는 시각 변형. 필요 시 floatPrecision: 5.

3. fill="none" stroke="currentColor" 미적용

outline 아이콘은 fill 없이 stroke. solid 아이콘은 stroke 없이 fill. 한 컴포넌트에 두 스타일 섞으면 색상 컨트롤 깨짐.

4. JSX 안 dash → camelCase

React 에서 stroke-widthstrokeWidth, clip-pathclipPath. SVG attribute 그대로 쓰면 warning.

5. aria-hidden 누락

의미가 텍스트로도 표현된 아이콘 (예: "복사" 버튼 옆 copy 아이콘) 은 aria-hidden="true". SR 가 중복 읽기 회피.

6. CSP 위반

inline SVG 안 style attribute 또는 <style> 태그가 style-src 'self' CSP 와 충돌. 외부 CSS 로 옮기거나 'unsafe-inline' 허용.

요약

  • 편집 도구 export → SVGO 로 60-80% 감소.
  • viewBox 유지, width/height 제거 → CSS 자유.
  • 작은 아이콘 inline (현재 표준), 큰 일러스트는 외부 + 캐시. 20+ 아이콘 은 sprite.
  • fill="currentColor" 로 테마 자동 추종.
  • 사용자 업로드 SVG 는 <img> 로 표시 또는 DOMPurify sanitize.
  • 아이콘 라이브러리 (lucide-react 등) 가 직접 관리보다 cost-effective.
가이드 목록으로