๐ขSVG๋?
SVG๋ 'Scalable Vector Graphics' ์ ์ฝ์ด๋ก
๊ฐ ์์น ๊ฐ์ ํ์ํ๋ ๋ฒกํฐ์ ๊ฐ์ ๋ฐฉ์์ 2์ฐจ์ ๊ทธ๋ํฝ์ฉ XML ๊ธฐ๋ฐ์ ํ์์ ์ด์ผ๊ธฐํ๋ค.
โ SVG๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋?
PNG๋ JPG๋ ๋นํธ๋งต ๊ธฐ๋ฐ์ ์ด๋ฏธ์ง๋ก ๊ฐ ํญ๋ชฉ์ ํ๋ ์ด์์ ์ ๋ณด ๋นํธ๋ฅผ ๊ฐ์ง๊ณ ์๋ ํํ์ด๋ค.
๋ฐ๋ฉด SVG๋ ๋ฒกํฐ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ ์ขํ์ ์ ์ ์ด์ด์ ๋ง๋ค์ด์ง๋ ๊ฐ๋ ์ด๋ค. ๋ฒกํฐ ๊ธฐ๋ฐ์ ์์ด์ฝ์ ํ๋๋ ์ถ์๋ฅผ ํด๋ ๊นจ์ง์ง ์๋ ๊ฒ๊ณผ ๊ฐ์ ์๋ฆฌ์ด๋ค.
โ ํ๋ก์ ํธ์์์ SVG ํ์ฉ ์ฌ๋ก
๋ด๊ฐ ์ฐธ์ฌํ ํ๋ก์ ํธ์์๋ MobileFooter ์ปดํฌ๋ํธ์ SVG ์์ด์ฝ์ ํ์ฉํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๋ค
ํ๋จ ๋ค๋น๊ฒ์ด์ ๋ฉ๋ด์์ ๊ฐ ์์ด์ฝ์ ํด๋ฆญํ๋ฉด fill์ด ์ฑ์์ง๋๋ก ํ์ก๊ณ css์ scale์ ์ด์ฉํด ํฌ๊ธฐ๋ฅผ ์์ฐ์ค๋ฝ๊ฒ ์ปค์ง๋๋ก ํ์๋ค.
export default function MobileFooter() {
const menuItems = [
{
href: '/',
label: '์นด๋',
icon: (
<svg
className={styles.svg}
width="51"
height="38"
viewBox="0 0 51 38"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1 19.8676C1 11.2095 1 6.88046 3.83129 4.19071C6.66261 1.50098 11.2195 1.50098 20.3333 1.50098H30C39.1137 1.50098 43.6708 1.50098 46.502 4.19071C49.3333 6.88046 49.3333 11.2095 49.3333 19.8676C49.3333 28.5257 49.3333 32.8549 46.502 35.5445C43.6708 38.2343 39.1137 38.2343 30 38.2343H20.3333C11.2195 38.2343 6.66261 38.2343 3.83129 35.5445C1 32.8549 1 28.5257 1 19.8676Z"
stroke="#9ca3af"
strokeWidth="3"
/>
<path
d="M20.3332 30.1982H10.6665"
stroke="#9ca3af"
strokeWidth="3"
strokeLinecap="round"
/>
<path
d="M15.4998 23.3105H10.6665"
stroke="#9ca3af"
strokeWidth="3"
strokeLinecap="round"
/>
<path
d="M1 15.2764H49.3333"
stroke="#9ca3af"
strokeWidth="3"
strokeLinecap="round"
/>
<path
d="M30 26.7548C30 24.5902 30 23.508 30.7078 22.8355C31.4157 22.1631 32.5549 22.1631 34.8333 22.1631C37.1118 22.1631 38.251 22.1631 38.9588 22.8355C39.6667 23.508 39.6667 24.5902 39.6667 26.7548C39.6667 28.9193 39.6667 30.0015 38.9588 30.674C38.251 31.3464 37.1118 31.3464 34.8333 31.3464C32.5549 31.3464 31.4157 31.3464 30.7078 30.674C30 30.0015 30 28.9193 30 26.7548Z"
stroke="#9ca3af"
strokeWidth="3"
/>
</svg>
),
},
{
href: '/travel',
label: '์ฌํ',
icon: (
<svg
className={styles.svg}
width="30"
height="32"
viewBox="0 0 30 33"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.3851 31.288L14.0056 28.2425C14.5494 27.7763 15.4506 27.7763 15.9945 28.2425L19.6149 31.288C20.4539 31.7075 21.4795 31.288 21.7902 30.3868L22.4739 28.3202C22.6448 27.8229 22.4739 27.0926 22.101 26.7197L18.5738 23.177C18.3097 22.9284 18.1077 22.4312 18.1077 22.0738V17.6454C18.1077 16.9928 18.5894 16.682 19.1953 16.9306L26.8246 20.2247C28.0211 20.7375 29 20.1004 29 18.7952V16.7908C29 15.7497 28.2231 14.5533 27.2597 14.1493L18.5738 10.4045C18.3252 10.2958 18.1077 9.96947 18.1077 9.68978V5.0283C18.1077 3.5677 17.0355 1.84295 15.7303 1.17481C15.2642 0.941731 14.7203 0.941731 14.2542 1.17481C12.949 1.84295 11.8768 3.58324 11.8768 5.04384V9.70532C11.8768 9.98501 11.6593 10.3113 11.4106 10.4201L2.74029 14.1648C1.77691 14.5533 1 15.7497 1 16.7908V18.7952C1 20.1004 1.97891 20.7375 3.17536 20.2247L10.8047 16.9306C11.3951 16.6665 11.8923 16.9928 11.8923 17.6454V22.0738C11.8923 22.4312 11.6903 22.9284 11.4417 23.177L7.91454 26.7197C7.54162 27.0926 7.3707 27.8074 7.54162 28.3202L8.2253 30.3868C8.50499 31.288 9.53052 31.7231 10.3851 31.288Z"
stroke="#9ca3af"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
},
{
href: '/banking',
label: '๋ฑ
ํน',
icon: (
<svg
className={styles.svg}
width="36"
height="36"
viewBox="0 0 36 36"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.3335 21.3333C1.3335 15.048 1.3335 11.9052 3.28611 9.95262C5.23875 8 8.38143 8 14.6668 8H21.3335C27.6188 8 30.7617 8 32.7142 9.95262C34.6668 11.9052 34.6668 15.048 34.6668 21.3333C34.6668 27.6187 34.6668 30.7615 32.7142 32.714C30.7617 34.6667 27.6188 34.6667 21.3335 34.6667H14.6668C8.38143 34.6667 5.23875 34.6667 3.28611 32.714C1.3335 30.7615 1.3335 27.6187 1.3335 21.3333Z"
stroke="#9ca3af"
strokeWidth="2"
/>
<path
d="M24.6668 7.99967C24.6668 4.85697 24.6668 3.28562 23.6905 2.30932C22.7142 1.33301 21.1428 1.33301 18.0002 1.33301C14.8575 1.33301 13.2861 1.33301 12.3098 2.30932C11.3335 3.28562 11.3335 4.85697 11.3335 7.99967"
stroke="#9ca3af"
strokeWidth="2"
/>
<path
d="M18.0003 26.8882C19.8413 26.8882 21.3337 25.6445 21.3337 24.1105C21.3337 22.5763 19.8413 21.3327 18.0003 21.3327C16.1593 21.3327 14.667 20.089 14.667 18.5548C14.667 17.0208 16.1593 15.7772 18.0003 15.7772M18.0003 26.8882C16.1593 26.8882 14.667 25.6445 14.667 24.1105M18.0003 26.8882V27.9993M18.0003 15.7772V14.666M18.0003 15.7772C19.8413 15.7772 21.3337 17.0208 21.3337 18.5548"
stroke="#9ca3af"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
),
},
];
return (
<div className={styles.mobile}>
<footer className={styles.footer}>
<nav className={styles.nav}>
<ul className={styles.menuList}>
{menuItems.map((item) => {
const isActive =
item.href === '/'
? pathname === item.href
: pathname.includes(item.href!);
return (
<li key={item.href} className={styles.menuItem}>
<Link href={item.href || '/'} className={styles.menuLink}>
<span
className={`${styles.iconWrapper} ${isActive ? styles.active : ''}`}
>
{item.icon}
</span>
<span
className={`${styles.label} ${isActive ? styles.active : ''}`}
>
{item.label}
</span>
</Link>
</li>
);
})}
</ul>
</nav>
</footer>
</div>
);
}
โ SVG ์ํฌํธ ๋ฐฉ์ ๋น๊ต
React์ Next.js์์๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ผ๋ก SVG๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ๊ฐ๊ฐ์ ์ฅ๋จ์ ์ ์ดํด๋ณด์!
1. Inline SVG
const MyIcon = () => (
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
</svg>
);
- ์ฅ์ :
- ์ง์ JSX์ ์์ฑํ๋ฏ๋ก ์ธ๋ถ ํ์ผ ์์กด์ฑ์ด ์๋ค.
- ๋์ ์ผ๋ก ์์ฑ์ ์กฐ์ ํ๊ธฐ ์ฉ์ดํ๋ค.
- ๋จ์ :
- ์ฝ๋ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง ์ ์๋ค.
- ๋ณต์กํ SVG์ ๊ฒฝ์ฐ JSX ์ฝ๋๊ฐ ๊ธธ์ด์ง ์ ์๋ค.
2. ํ์ผ ์ํฌํธ
import MyIcon from './icon.svg';
const App = () => <MyIcon />;
- ์ฅ์ :
- SVG ํ์ผ์ ๋ณ๋๋ก ๊ด๋ฆฌํ ์ ์์ด ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๋ค.
- SVGR์ ์ค์ ํ๋ฉด SVG๋ฅผ React ์ปดํฌ๋ํธ์ฒ๋ผ ์ฌ์ฉํ ์ ์๋ค.
- ๋จ์ :
- ๋น๋ ๋๊ตฌ(Webpack, Vite ๋ฑ)์ ์ถ๊ฐ ์ค์ ์ด ํ์ํ๋ค.
3. CSS ๋ฐฑ๊ทธ๋ผ์ด๋ ์ด๋ฏธ์ง
.icon {
background-image: url('./icon.svg');
width: 24px;
height: 24px;
}
- ์ฅ์ :
- ์คํ์ผ ํ์ผ์์ SVG๋ฅผ ๊ด๋ฆฌํ๋ฏ๋ก ๋ ์ด์์๊ณผ ์คํ์ผ์ ๋ถ๋ฆฌํ ์ ์๋ค.
- ๋จ์ :
- SVG์ ์์์ด๋ ํฌ๊ธฐ๋ฅผ ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๊ธฐ ์ด๋ ต๋ค.
โ React์์ SVG ์คํ์ผ๋ง
1. ์์ฑ์ ํ์ฉํ ๋์ ์คํ์ผ๋ง
React์์๋ width, height, fill, stroke ๊ฐ์ SVG ์์ฑ์ props๋ก ์ ๋ฌํ์ฌ ๋์ ์ผ๋ก ์กฐ์ ํ ์ ์๋ค.
const DynamicIcon = ({ size = 24, color = 'black' }) => (
<svg width={size} height={size} fill={color} xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" stroke="black" strokeWidth="2" />
</svg>
);
2. CSS๋ฅผ ํตํ ์คํ์ผ๋ง
CSS ๋ชจ๋ ๋๋ Tailwind CSS๋ฅผ ์ฌ์ฉํ๋ฉด SVG์ ์คํ์ผ์ ์ฝ๊ฒ ์ ์ฉํ ์ ์๋ค.
import styles from './Icon.module.css';
const StyledIcon = () => (
<svg className={styles.icon} xmlns="http://www.w3.org/2000/svg">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
</svg>
);
/* Icon.module.css */
.icon { fill: blue; transition: fill 0.3s; }
.icon:hover { fill: red; }
โ SVG ์ต์ ํ
1. SVGO๋ฅผ ํ์ฉํ ์ต์ ํ
SVG ํ์ผ์ ์ต์ ํํ๋ฉด ๋ถํ์ํ ์์ฑ๊ณผ ์ฝ๋๊ฐ ์ ๊ฑฐ๋์ด ์ฑ๋ฅ์ด ํฅ์๋๋ค.
- ๋๊ตฌ: SVGO
- ์ต์ ํ ๋ฐฉ๋ฒ:
npx svgo ./icon.svg --output ./icon.optimized.svg
2. ์ปดํฌ๋ํธํ
SVG๋ฅผ React ์ปดํฌ๋ํธ๋ก ๋ณํํ๋ฉด ์ฌ์ฌ์ฉ์ฑ๊ณผ ์ฝ๋ ๊ด๋ฆฌ๊ฐ ํธ๋ฆฌํด์ง๋ค.
import React from 'react';
const Icon = ({ color = 'black' }) => (
<svg fill={color} xmlns="http://www.w3.org/2000/svg">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" />
</svg>
);
export default Icon;
โ Next.js ํ๊ฒฝ์์์ SVG ์ฌ์ฉ ํ
1. ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง (SSR)
Next.js์์ SVG ์ปดํฌ๋ํธ๋ฅผ SSR๋ก ๋ ๋๋งํ๋ ค๋ฉด SVGR ์ค์ ์ ์ถ๊ฐํด์ผ ํ๋ค.
next.config.js
module.exports = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack'],
});
return config;
},
};
2. Lazy Load์ Dynamic Import
SVG ์์ด์ฝ์ ๋์ ์ผ๋ก ๋ก๋ํ๋ฉด ์ด๊ธฐ ๋ก๋ฉ ์๋๋ฅผ ๊ฐ์ ํ ์ ์๋ค.
import dynamic from 'next/dynamic';
const DynamicIcon = dynamic(() => import('./MyIcon'), { ssr: false });
const App = () => <DynamicIcon />;
โ ์ค์ ์ฌ์ฉ ์ฌ๋ก์ ํ์ฅ
์ ๋๋ฉ์ด์ ์ถ๊ฐ - SVG์ ๊ฐ๋จํ ์ ๋๋ฉ์ด์ ์ ์ถ๊ฐํ๋ฉด ๋์ฑ ์๋๊ฐ ์๋ UI๋ฅผ ๋ง๋ค ์ ์๋ค.
const AnimatedIcon = () => (
<svg xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" stroke="black" strokeWidth="3" fill="red">
<animate attributeName="r" from="40" to="20" dur="1s" repeatCount="indefinite" />
</circle>
</svg>
);
์ฐธ๊ณ ์๋ฃ
'Frontend > ๊ธฐํ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Electron์ด๋? (0) | 2024.09.17 |
---|