
์๋ฌธ: A Friendly Introduction to SVG
SVG(Scalable Vector Graphics)๋ JPG, PNG์ฒ๋ผ ์ด๋ฏธ์ง ํฌ๋งท์ ํ๋์ ๋๋ค. ํ์ง๋ง SVG๋ ๋ฒกํฐ ๊ธฐ๋ฐ ์ด๋ฏธ์ง ํฌ๋งท์ผ๋ก, XML ๋ฌธ๋ฒ์ ํตํด ๊ทธ๋ ค์ง๋๋ค.
๐ ์ฆ, ํฝ์ ๋จ์๋ก ์์ ์ง์ ํ๋ ๊ฒ ์๋๋ผ, โ๋ฌด์์ ์ด๋ป๊ฒ ๊ทธ๋ฆด ๊ฒ์ธ์งโ์ ๋ํ ๋ช ๋ น์ด(๊ทธ๋ฆฌ๊ธฐ ์ง์นจ)๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
SVG๋ <img src="..."/>๋ก ์ฝ์
ํ ์๋ ์์ง๋ง, ์ง์ ํ ํ์ inline SVG์ ์์ต๋๋ค.
<img
alt="return to homepage"
src="/images/home.svg"
/>
์ด๋ ๊ฒ HTML ์์ ์ง์ SVG๋ฅผ ์์ฑํ๋ฉด, JavaScript๋ CSS๋ก DOM์ฒ๋ผ ๋ค๋ฃฐ ์ ์์ต๋๋ค.
<style>
circle {
fill: hotpink;
transition: r 400ms, cy 600ms;
}
button:hover circle {
r: 50;
cy: 100;
}
</style>
<button>
<svg width="100" height="100">
<circle r="30" cx="50" cy="50" />
</svg>
</button>
<line x1="80" y1="80" x2="200" y2="200" stroke="blue" stroke-width="5" />
x1, y1: ์์์ x2, y2: ๋์ stroke: ์ ์stroke-width: ์ ๋๊ป<rect x="60" y="100" width="180" height="100" stroke="green" fill="none" stroke-width="5"/>
x, y: ์ข์๋จ ๊ธฐ์ค ์์นwidth, height: ํฌ๊ธฐrx, ry: ๋ฅ๊ทผ ๋ชจ์๋ฆฌ ๋ฐ์ง๋ฆ<circle cx="140" cy="140" r="70" stroke="purple" fill="none" stroke-width="5"/>
cx, cy: ์ค์ฌ ์์นr: ๋ฐ์ง๋ฆ<ellipse cx="150" cy="150" rx="75" ry="50" stroke="orange" fill="none" stroke-width="5"/>
rx, ry: ์ํ/์์ง ๋ฐ์ง๋ฆ<polygon points="60,100 100,180 140,140 180,180 220,100" />
points: ์ขํ๋ค์ ๋์ด๐ ์ฐธ๊ณ : ์ ๋ค๊ฐํ(์: ์ก๊ฐํ)์ ๋ง๋ค๋ ค๋ฉด ์ผ๊ฐํจ์๋ฅผ ์ฌ์ฉํด ์ขํ๋ฅผ ๊ณ์ฐํด์ผ ํฉ๋๋ค.
viewBox<svg
width="300"
viewBox="0 0 300 220"
>
<circle
cx="150"
cy="110"
r="60"
stroke="var(--gold)"
stroke-width="10"
/>
</svg>
viewBox="minX minY width height" ํ์SVG๋ fill, stroke, stroke-width ๋ฑ์ ํ๋ฆฌ์ ํ
์ด์
์์ฑ์ผ๋ก ์คํ์ผ๋งํฉ๋๋ค.
<circle
cx="100"
cy="100"
r="50"
stroke="hsl(45 100% 50%)"
stroke-width="6"
stroke-dasharray="20, 14"
stroke-linecap="round"
/>
stroke-dasharray: ์ ์ /๊ฐ๊ฒฉ ํจํดstroke-linecap: ์ ์ ๋ ๋ชจ์ (butt, round, square)SVG์ stroke, stroke-width, stroke-dasharray ๋ฑ์ ์์ฑ์ CSS์์ transition๊ณผ animation์ผ๋ก ๋ถ๋๋ฝ๊ฒ ๋ณํ์ํฌ ์ ์์ต๋๋ค. ์ด๋ก ์ธํด, SVG๋ ๋จ์ํ ์ด๋ฏธ์ง ์ด์์ ์ธํฐ๋ํฐ๋ธํ ์ ๋๋ฉ์ด์
ํํ ๋๊ตฌ๊ฐ ๋ฉ๋๋ค.
@keyframes spin {
from {
stroke-dashoffset: 0;
}
to {
stroke-dashoffset: -100;
}
}
circle {
stroke: hotpink;
stroke-width: 4;
stroke-dasharray: 10, 10;
animation: spin 1s linear infinite;
}
stroke-dasharray: 10, 10: 10px ์ , 10px ๊ณต๋ฐฑ์ ๋ฐ๋ณตํ๋ ์ ์ ์ ๋ง๋ญ๋๋ค.stroke-dashoffset: ์ด ๊ฐ์ ์ ๋๋ฉ์ด์
ํ๋ฉด ์ ์ ์ด ์์ง์ด๋ ๊ฒ์ฒ๋ผ ๋ณด์
๋๋ค.๐ก ๋ฐ๋ณต ์ ๋๋ฉ์ด์
์ด ๋๊ธฐ์ง ์๊ฒ ํ๋ ค๋ฉด dasharray์ ์ดํฉ๊ณผ dashoffset์ ๋ฒ์๋ฅผ ์ผ์น์์ผ์ฃผ๋ ๊ฒ์ด ์ข์ต๋๋ค.
const el = document.querySelector('polygon');
const length = el.getTotalLength();
el.style.strokeDasharray = `${length} ${length}`;
el.style.strokeDashoffset = length;
polygon {
stroke: steelblue;
stroke-width: 3;
fill: none;
transition: stroke-dashoffset 3s ease;
}
getTotalLength()๋ SVG ๊ฒฝ๋ก ์ ์ฒด ๊ธธ์ด๋ฅผ ๊ณ์ฐํฉ๋๋ค.strokeDasharray์ strokeDashoffset์ ๋์ผํ๊ฒ ์ค์ ํ ๋ค offset์ 0์ผ๋ก ์ค์ด๋ฉด ์ธ๊ณฝ์ ์ด ๊ทธ๋ ค์ง๋ ๋ฏํ ์ฐ์ถ์ด ๊ฐ๋ฅํฉ๋๋ค.๐ฏ ์ด ๋ฐฉ๋ฒ์ path, circle, polygon ๋ฑ ๋๋ถ๋ถ์ SVG ์์์ ์ ์ฉ ๊ฐ๋ฅํ๋ฉฐ, ๋ก๋ฉ ์ ๋๋ฉ์ด์
์ด๋ ์ธํธ๋ก ํจ๊ณผ๋ก ์ ์ฉํฉ๋๋ค.
pathLength ์์ฑ)<style>
polygon {
stroke-dasharray: 100, 10000;
stroke-dashoffset: 100;
transition: stroke-dashoffset 3000ms;
}
</style>
<svg viewBox="0 0 280 320">
<polygon
pathLength="100"
points="..."
/>
</svg>
pathLength="100"์ ๊ฒฝ๋ก ์ ์ฒด ๊ธธ์ด๋ฅผ 100์ผ๋ก ๊ฐ์ ์ฌ์ ์ํฉ๋๋ค.stroke-dasharray, stroke-dashoffset ๊ฐ์ ๋ค๋ฃฐ ๋ ํจ์ฌ ์ง๊ด์ ์ผ๋ก ์์ฑํ ์ ์์ต๋๋ค.๐ ๋ค๋ง, ์ค์ ๊ธธ์ด์ ๋ค๋ฅด๊ฒ ์ค์ ํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋๋ฒ๊น ํ ๋ ํผ๋์ ์ค ์ ์์ต๋๋ค. ๋์ SVG๋ฅผ ๋ค๋ฃฐ ๋๋ง ์ฌ์ฉ์ ์ถ์ฒํฉ๋๋ค.
<path> ์์์ด ๊ธ์์๋ <path>๋ฅผ ๋ค๋ฃจ์ง ์์์ง๋ง, SVG์ ์ง์ ํ ํ์ ์ด ์์์ ์์ต๋๋ค.
d="M 10 10 L 50 50")๋ค์ ํฌ์คํธ์์ <path>์ ๋ํ ์์ธํ ์์์ ์์ฉ๋ฒ์ ์๊ฐํ ์์ ์
๋๋ค.
SVG๋ ์น ๊ฐ๋ฐ์์ ๊ผญ ์์์ผ ํ ํ์ ๊ธฐ์ ์ ๋๋ค. ์ด ๊ธ์ด SVG ์ ๋ฌธ์ ์ฅ๋ฒฝ์ ๋ฎ์ถ๋ ๋ฐ ๋์์ด ๋์๊ธธ ๋ฐ๋๋๋ค.
SVG๋ฅผ ํ์ฉํ ์ธํฐ๋์
, ์ ๋๋ฉ์ด์
, ๋ฐ์ํ UI๊น์ง!
์ง๊ธ ์์ํด๋ ๋ฆ์ง ์์ต๋๋ค. โจ