SVG 렌더링 기법과 튜토리얼

Visual UI
2025.11.14
SVG 렌더링 기법과 튜토리얼

SVG : Scalable Vector Graphics

확장 가능한 벡터 그래픽, W3C XML의 특수 언어

1. Image Tag + SVG

<img alt="some" src="/images/some.svg" />
  • flicker 현상
  • cache (초기 로딩은 느림, 이미지 변경 시 파라미터 추가)
  • 단점: css 불가

2. Inline SVG

  • flicker 현상 없음
  • first-class in the DOM
    • css 가능 : fill, stroke, circle{r: ;cy: ;}, transition
    • Event Listeners 가능 (각 요소마다)
    • Javscript 동적 제어 가능
    • Design Software(Figma, Illustrator)로 merge(mash) 시 색상수정, animation 불가

svg

<svg width="" height="" viewBox="min-x min-y width height"> ... </svg>

  • viewBox: internal coordinate system

Line

<line x1="" y1="" x2="" y2="" stroke="" stroke-width="" />

  • start point x1 y1 / end point x2 y2

Rectangles

<rect x="" y="" width="" height="" rx="" ry="" fill="" stroke="" stroke-width="" />

  • positioned x y / grow width height / 반지름 (horizontal, vertical) rx ry
ry rx <rect x="10" y="10" width="150" height="150" rx="50" ry="30" fill="none" stroke="#28C86B" stroke-width="3" />
  • center line (inline or outline으로 설정 불가)
  • width 또는 height 0 일때 전체 사라짐 (border 남지 않음)

Circles

<circle cx="" cy="" r="" fill="" stroke="" stroke-width="" />

  • 중심점 positioned cx cy / 반지름 r
  • 반지름 0 일때 전체 사라짐 (border 남지 않음)

Ellipses

<ellipse cx="" cy="" rx="" ry="" fill="" stroke="" stroke-width="" />

  • 중심점 positioned cx cy / 반지름 (horizontal, vertical) rx ry
  • 반지름 0 일때 전체 사라짐 (border 남지 않음)

Polygons

<polygon points="x,y x,y x,y" fill="" stroke="" stroke-width="" />

  • points 좌표 나열 (보기 편하게 comma 명시)
    , 생략해도 최적화에 큰 영향 없음 (web servers gzip compression)
<line x1="10" y1="20" x2="40" y2="20" stroke-width="2" stroke="#2e3f6f" />
<rect x="50" y="20" width="50" height="50" rx="10" ry="10" fill="#879bd7" stroke="#2e3f6f" stroke-width="2" />
<rect x="110" y="20" width="0" height="50" rx="10" ry="10" fill="#87d79b" stroke="#2e3f6f" stroke-width="2" /> // disappear
<circle cx="150" cy="50" r="20" fill="#879bd7" stroke="#2e3f6f" stroke-width="2" />
<ellipse cx="200" cy="50" rx="20" ry="40" fill="#879bd7" stroke="#2e3f6f" stroke-width="2" />
<polygon points="250,20 250,100 300, 20" fill="#879bd7" stroke="#2e3f6f" stroke-width="2" />
// disappear

Path

  • d : Data
  • M : Move (Start x,y)
  • L : Line(2 Points)
<path
	d="
		M 10,10  < Move Start
		L 90,90  < Line
	"
/>
  • Q : Quadratic Bezier curves (3 Points) : 2차 베지어 곡선
<path
	d="
		M 10,10  < Point 1
		Q 10,90  < Point 2 (Curve Point)
			90,90  < Point 3
	"
/>
  • C : Cubic Bezier curves (4 Points) : 3차 베지어 곡선
<path
	d="
		M 10,10  < Point 1
		C 10,90  < Point 2 (Curve Point 1)
			90,10  < Point 3 (Curve Point 2)
			90,90  < Point 4
	"
/>
  • T : Smooth Quadratic Bezier curves (Q + 1 point)
M 10,10 Q 10,90 50,50 Q 100,50 90,90 M 10,10 Q 10,90 50,50 T 90,90
  • S : Smooth Cubic Bezier curves (C + 2 points)
M 10,10 C 50,20 10,70 50,60 M 10,10 C 50,20 10,70 50,60 S 60,80 90,90
  • A : Arcs [rx],[ry] [rotation] [large-arc-flag] [sweep-flag] [end-x],[end-y]
    • [rx], [ry] 반지름 : 반지름 길이시작-끝점 길이보다 짧을 경우에도 비율(rx : ry) 계산하여 그림
    • [rotation] 0 deg
    • [large-arc-flag] 0(short path) : 1(long path) : 길이가 정확히 같으면 달라지지 않음
    • [sweep-flag] 0(counter-clockwise) : 1(clockwise)
    • [end-x], [end-y] 끝점
<path
	d="
		M 10,20
		L 30 20 // 시작점
		A 30,30 0 0 0 60,70
	"
/>
M 10,20 L 30,20 A 30,30 0 0 0 60,70 large-arc-flag A 30,30 0 1 0 60,70 sweep-flag A 30,30 0 0 1 60,70
  • Z : 시작점과 join
<path
	d="
		M 20,20
		A 1,1 0 0 0 60,50
		Z
	"
	fill="none" stroke="#2e3f6f" stroke-width="2"
/>
  • m, l, q, c, t, s, a : 소문자
    • 상대좌표 (Relative)

Draw Trick

stroke-dasharray stroke-dashoffset 속성으로 Draw animation

  • stroke-dasharray(dash 길이 + 간격) = stroke-dashoffset
element{
	stroke-dasharray: 도형 둘레;
	animation:elementDraw 3s infinite alternate;
}
@keyframes elementDraw1{
	0%{stroke-dashoffset: 0;}
	100%{stroke-dashoffset: 도형 둘레;}
}

1. 도형 둘레 구한 후 지정 element.getTotalLength()

<polygon points="100,32 116,83 170,83 126,116 144,168 100,135 56,168 73,116 30,83 83,83" fill="none" stroke="#2e3f6f" stroke-width="2" />
const polygonLength = document.querySelector('polygon').getTotalLength();
// polygonLength: 544
polygon{
	stroke-dasharray: 544; //polygonLength
	animation:elementDraw1 3s infinite alternate;
}
@keyframes elementDraw1{
	0%{stroke-dashoffset: 544;}
	100%{stroke-dashoffset: 0;}
}

2. 길이 재정의 pathLength

<polygon pathLength="100" points="100,32 116,83 170,83 126,116 144,168 100,135 56,168 73,116 30,83 83,83" fill="none" stroke="#2e3f6f" stroke-width="2" />
polygon{
	stroke-dasharray: 100; // 실제 길이 544지만 100으로 재정의
	animation:elementDraw2 3s infinite alternate;
}
@keyframes elementDraw2{
	0%{stroke-dashoffset: 100;}
	100%{stroke-dashoffset: 0;}
}

3. Inline SVG Sprites

img Sprites 비슷 → img는 HTTP2에서 해결 : 여러 파일 병렬 전송

  • <defs> 나중에 사용할 SVG 그래픽 객체를 저장 (직접 렌더링 되지 않고 <use>로 참조하여 렌더링)
  • <symbol> 인스턴스화 할 SVG 그래픽 템플릿 객체 정의
  • <use> SVG 문서 내에서 노드를 가져와 복제

예시 1

sprite.svg
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
		<symbol id="fileAdd">
			<path d="M2.5 5V1.5C2.5 1.23478 2.60536 0.98043 2.79289 0.792893C2.98043 0.605357 3.23478 0.5 3.5 0.5H10L13.5 4V12.5C13.5 12.7652 13.3946 13.0196 13.2071 13.2071C13.0196 13.3946 12.7652 13.5 12.5 13.5H7.5" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
			<path d="M3.5 7.5V13.5" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
			<path d="M0.5 10.5H6.5" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
		</symbol>
    <symbol id="fileRemove">
			<path d="M2.5 7.5V1.5C2.5 1.23478 2.60536 0.98043 2.79289 0.792893C2.98043 0.605357 3.23478 0.5 3.5 0.5H10L13.5 4V12.5C13.5 12.7652 13.3946 13.0196 13.2071 13.2071C13.0196 13.3946 12.7652 13.5 12.5 13.5H6.5" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
			<path d="M0.5 10.5H5.5" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
		</symbol>
  </defs>
</svg>
index.html
<head>
  <link rel="preload" href="sprite.svg" as="image" type="image/svg+xml">
</head>
<svg>
	<use href="#fileRemove" />
</svg>
  • preload 로 파일 캐시, 성능 향상
  • xmlns:xlink="http://www.w3.org/1999/xlink" SVG는 XML 기반이기 때문에 독립된 SVG파일(sprite.svg)일 경우 최상단에 정의

예시 2 : CustomElements 사용자 정의 요소

k-svg.js
const ksvgSprite = ()=>{
	if (document.getElementById('ksvgSprite')) return;
	const sprite = document.createElement('div');
	sprite.id = "ksvgSprite";
	sprite.style.display="none";
	sprite.innerHTML=`
		<svg>
			<defs>
				...
			</defs>
		</svg>
	`
	document.body.appendChild(sprite);
}

class KSvg extends HTMLElement{
	connectedCallback(){
		ksvgSprite();

		const icon = this.getAttribute('icon');
		const size = this.getAttribute('size');
		if (!icon || !size) return false;
		
		const numericSize = parseInt(size, 10);
		this.style.display = "inline-block"
		this.style.width = numericSize + 'px';
		this.style.height = numericSize + 'px';
		const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
		svg.setAttribute('width', numericSize);
		svg.setAttribute('height', numericSize);
		svg.setAttribute('fill', 'none');
		svg.setAttribute('viewBox', `0 0 14 14`);
		const use = document.createElementNS("http://www.w3.org/2000/svg", "use");
		use.setAttribute("href", `#${icon}`);
		use.setAttribute("xlink:href", `#${icon}`);
		svg.appendChild(use);
		this.appendChild(svg);
	}
}
customElements.define('k-svg', KSvg);
index.html
<k-svg icon="fileRemove" size="42"></k-svg>

© 2026 Choi Seohee. All Rights Reserved.