[React] background-image์ svg ์ฌ์ฉํ๊ธฐ (inline SVG)
์์น๋ณ ํ์ผ ๊ฒฝ๋ก ๊ธฐ์ค
- JSX ์๋ฆฌ๋จผํธ ์์ฑ์ ๋ฃจํธ ํด๋ ๊ธฐ์ค :
public
- CSS ํ์ผ ๋ฃจํธ ํด๋ ๊ธฐ์ค :
src
- ํ์ผ ์ต์๋จ
import
๊ตฌ๋ฌธ :src
ํด๋๋ง ์ฒ๋ฆฌ ๊ฐ๋ฅ(public
ํด๋์ ์๋ ํ์ผ์ ๋ถ๊ฐ) <img>
ํ๊ทธsrc
์์ฑ(JSX ํ๊ทธ ์์ฑ)์src
ํด๋์ ์๋ ์ด๋ฏธ์ง ํ์ผ์ ์ง์ ํ๋ ค๋ฉด…
- ํ์ผ ์ต์๋จ์์ ๋ถ๋ฌ์จ ์ด๋ฏธ์ง ํ์ผ์
src
์์ฑ์ ํ ๋นํ๊ฑฐ๋, src
์์ฑ ์์์require()
์ฌ์ฉ e.g.<img src={require('...').default} />
- ํ์ผ ์ต์๋จ์์ ๋ถ๋ฌ์จ ์ด๋ฏธ์ง ํ์ผ์
๋ฌธ์ ์ํฉ
JSX ์๋ฆฌ๋จผํธ ์์ฑ์ ๋ฃจํธ ํด๋ ๊ธฐ์ค์ public
ํด๋๋ฏ๋ก ์ด๋ฏธ์ง ํ์ผ์ด src
ํด๋์ ์๋ค๋ฉด ํ์ผ ์ต์๋จ์์ ์ด๋ฏธ์ง ํ์ผ์ import
ํ ํ ์ธ๋ผ์ธ ์คํ์ผ url()
ํจ์์ ์ฌ์ฉํ ์ ์๋ค. *.png
, *.webp
๊ฐ์ ์ด๋ฏธ์ง ํ์ผ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก ์ ์๋ํ๋ค.
// src/assets/image ํด๋์ ์๋ profile-image.png ํ์ผ import
import ArrowDown from '../assets/image/arrow-down.png';
// ์ปดํฌ๋ํธ ๋ฆฌํด๋ฌธ
<select
style={{ backgroundImage: `url(${ArrowDown})` }}
className="bg-no-repeat bg-right pr-4"
>
...
</select>;
ํ์ง๋ง ์์ ๋์ผํ ๋ฐฉ๋ฒ์ผ๋ก .svg
ํ์ผ์ ์ ์ฉํด๋ณด๋ฉด ์ด๋ฏธ์ง๊ฐ ์๋์จ๋ค. ๐ข
ํด๊ฒฐ ๋ฐฉ๋ฒ
ํด๊ฒฐ ๋ฐฉ๋ฒ์ 2๊ฐ์ง๊ฐ ์๋ค.
- svg ํ์ผ์ Data URI์์ ์ฌ์ฉํ ์ ์๋ ๋ฌธ์์ด๋ก ๋ณํ
- CSS ํ์ผ์ ์ปค์คํ
ํด๋์ค๋ฅผ ๋ง๋ค๊ณ
url()
ํจ์์ svg ํ์ผ ๊ฒฝ๋ก ๋ช ์ (SSR / SSG์์ ์๋ ์๋ ์์)
๋ฐฉ๋ฒ 1 — Data URI ์ฌ์ฉ
๐ก ์ด๋ฏธ์ง ํ์ผ์ base64 URI๋ก ๋ฐ๊ฟ์ฃผ๋ url-loader ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋ค.
svg ํ์ผ์ Data URI์์ ์ฌ์ฉํ ์ ์๋ ๋ฌธ์์ด๋ก ๋ณํํ๋ฉด CSS url()
ํจ์์ ์ฌ์ฉํ ์ ์๋ค. url()
ํจ์ ์ธ์์ ์ด๋ฏธ์ง ํ์ผ์ ์๋ / ์ ๋ ๊ฒฝ๋ก, ์น ๋ฆฌ์์ค ์ฃผ์ ํน์ data URL / blob URL์ ์ถ๊ฐํ ์ ์๋ค.
import ArrowDown from '../assets/image/arrow-down.svg';
import { renderToStaticMarkup } from 'react-dom/server';
// ์ปดํฌ๋ํธ ๋ณธ๋ฌธ
// svg ํ์ผ์ Data URI์์ ์ฌ์ฉํ ์ ์๋ ๋ฌธ์์ด๋ก ๋ณํ
const svgString = encodeURIComponent(renderToStaticMarkup(<ArrowDown />));
// ์ปดํฌ๋ํธ ๋ฆฌํด๋ฌธ
<select style={{ backgroundImage: `url("data:image/svg+xml,${svgString}")` }}>
...
</select>;
Percent Encoding
URI์์ ๋ฌธ๋ฒ์ ์๋ฏธ๋ฅผ ๊ฐ๋ ๋ฌธ์๋ฅผ ์์ฝ ๋ฌธ์๋ผ๊ณ ํ๋ค. ์๋ฅผ๋ค์ด URI์์ &
์ฐํผ์๋๋ AND ์๋ฏธ๋ฅผ ๊ฐ๋๋ค. ๋ง์ฝ ์ฟผ๋ฆฌ์คํธ๋ง(?key=value
) value ๊ฐ์ &
๊ฐ์ ์์ฝ ๋ฌธ์๋ฅผ ๋ฌธ๋ฒ์ ์๋ฏธ๊ฐ ์๋ ๋ฌธ์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ค๋ฉด ์ธ์ฝ๋ฉ(์ด์ค์ผ์ดํ)์ด ํ์ํ๋ค.
๐๏ธ ์์ฝ ๋ฌธ์ ๋ชฉ๋ก — URI์์ ๋ฌธ๋ฒ์ ์๋ฏธ๋ฅผ ๊ฐ์ง / ๋ฌธ์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ค๋ฉด ์ธ์ฝ๋ฉ ํ์
!
*
'
(
)
;
:
@
&
=
+
$
,
/
?
#
[
]
๐๏ธ ๋น์์ฝ ๋ฌธ์ ๋ชฉ๋ก — ์ธ์ฝ๋ฉ ํ์ํ์ง ์์
A-Z
a-z
0-9
-
_
.
~
ํ๊ธ, ํ์ ๊ฐ์ non-ASCII ๋ฌธ์๋ฅผ URI์์ ์ฌ์ฉํ๋ ค๋ฉด ๋ง์ฐฌ๊ฐ์ง๋ก ์ธ์ฝ๋ฉ์ด ํ์ํ๋ค. ์ด์ฒ๋ผ URI์์ ์ฌ์ฉํ ์ ์๋ ๋ฌธ์์ด์ ์ฌ์ฉํ ์ ์๋๋ก(ํน์ ์์ฝ ๋ฌธ์๋ฅผ ๋ฌธ๋ฒ์ ์๋ฏธ๊ฐ ์๋ ๋ฌธ์ ๊ทธ๋๋ก ์ฌ์ฉํ ๋) ๋ณํํ๋ ๊ณผ์ ์ Percent Encoding(URL Encoding)์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
Percent Encoding ์ธ์ฝ๋ฉํ ๋ฌธ์๋ %
๋ก ์์ํ๊ณ ๊ทธ๋ค์ 16์ง์ ์ซ์๋ฅผ ๋ถ์ฌ์ ํํํ๋ค. e.g. &
→ %26
encodeURIComponent / encodeURI
encodeURIComponent
๋ฉ์๋๋ ๋ฌธ์์ด์ UTF-8๋ก ์ด์ค์ผ์ดํํ ๋ฌธ์์ด์ ๋ฐํํ๋ค. ์ฆ URI์์ ์ฌ์ฉํ ์ ์๋๋ก Percent Encodingํ ๋ฌธ์์ด์ ๋ฐํํ๋ค. ์ด์ ๋น์ทํ encodeURI
๋ฉ์๋๋ ์๋ค. ์ด ๋ ๋ฉ์๋์ ์ํ ๊ธฐ๋ฅ์ ๋์ผํ์ง๋ง ์ด์ค์ผ์ดํํ์ง ์๋ ๋ฌธ์์ด์ ์ฐจ์ด๊ฐ ์๋ค.
const music = encodeURIComponent('Rock&Roll'); // 'Rock%26Roll'
const url = `https://google.com/search?q=${music}`;
- encodeURIComponent : ์ฃผ๋ก ์ฟผ๋ฆฌ์คํธ๋ง(
?key=value
)์ value ๋ถ๋ถ์ ์ธ์ฝ๋ฉํ ๋ ์ฌ์ฉ
- ์ ์ธ ๋ฌธ์ :
A-Z
a-z
0-9
-
_
.
!
~
*
'
(
)
- ๋์ฝ๋ฉ ๋ฉ์๋ :
decodeURIComponent
- ์ ์ธ ๋ฌธ์ :
- encodeURI : URI ์ ์ฒด๋ฅผ ์ธ์ฝ๋ฉํ ๋ ์ฌ์ฉ (URI๋ฅผ ๊ตฌ์ฑํ๋๋ฐ ํ์ํ ์์ฝ/๋น์์ฝ ๋ฌธ์๋ ์ธ์ฝ๋ฉ ์ํจ)
- ์ ์ธ ๋ฌธ์ :
A-Z
a-z
0-9
;
,
/
?
:
@
&
=
+
$
-
_
.
!
~
*
'
(
)
#
- ๋์ฝ๋ฉ ๋ฉ์๋ :
decodeURI
- ์ ์ธ ๋ฌธ์ :
renderToStaticMarkup
React ์๋ฆฌ๋จผํธ์ ๋ํด ์ ์ HTML(HTML ๋ฌธ์์ด)์ ์์ฑํ๋ ๋ฉ์๋. data-reactroot
์ฒ๋ผ ๋ฆฌ์กํธ ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉํ๋ DOM ์ดํธ๋ฆฌ๋ทฐํธ(data-*
)๋ ๋ง๋ค์ง ์๋๋ค. ๋ฐ๋ผ์ ReactDOM.hydrate()
๋ฅผ ์ฌ์ฉํด ์ํธ์์ฉํ ์ ์๋ ์ด๋ฒคํธ๋ฅผ ์ฃผ์
ํ ์ ์๋ค.
const staticMarkup = renderToStaticMarkup(<h1>hello world</h1>);
console.log(staticMarkup); // <h1>hello world</h1>
console.log(typeof staticMarkup); // string
Data URI
data:[<mime type>][;charset=<charset>][;base64],<encoded data>
Data URI ์คํด(scheme)์ data:
์ ๋์ฌ๊ฐ ๋ถ์ ๋ฌธ์์ด๋ก, ํ์ผ์ ๋ฌธ์์ด๋ก ๋ณํํ ๊ฒ์ผ๋ก ์๊ฐํ๋ฉด ๋๋ค. ์์ ์ด๋ฏธ์ง ๋ฑ์ ํ์ผ์ ๋ฌธ์์ ์ธ๋ผ์ธ์ผ๋ก ๋ฃ๊ธฐ ์ํด ์ฌ์ฉํ๋ค. ์ด๋ฏธ ๋ฌธ์์ ํฌํจํ๊ธฐ ๋๋ฌธ์ ์๋ฒ์ ์์ฒญํ์ง ์๊ณ ํ์ผ์ ์ฌ์ฉํ ์ ์๋ค. Data URI๋ ์ด๋ฏธ์ง ํ๊ทธ์ src
์์ฑ์ด๋ CSS ์์ฑ์ url
ํจ์์์ ์ฌ์ฉํ ์ ์๋ค.
{ backgroundImage: `url("data:image/svg+xml,${svgString}")` }
๋ฐ์ดํฐ๊ฐ ํ
์คํธ ํ์์ด๋ฉด(React์์ ์ ๊ณตํ๋ renderToStaticMarkup
๋ฉ์๋๋ฅผ ์ฌ์ฉํด React ์๋ฆฌ๋จผํธ → HTML ๋ฌธ์์ด๋ก ๋ณ๊ฒฝ), ๋ฐ์ดํฐ๋ฅผ ์ด์ค์ผ์ดํํ ํ(encodeURIComponent
๋ฉ์๋ ์ฌ์ฉ) MIME ํ์
์ ๋ง์ถฐ์ ๋ฐ๋ก ์๋ฒ ๋ํ ์ ์๋ค. *.svg
ํ์ผ์ MIME ํ์
์ image/svg+xml
์ด๋ค.
๐ก ๋ฐ์ดํฐ ํ์
์ ์๋ตํ๋ฉด text/plain;charset=US-ASCII
์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ค.
๋ฐ์ดํฐ๊ฐ ์ด๋ฏธ์ง ํ์ผ์ด๋ผ๋ฉด base64(๋ฐ์ดํฐ๋ฅผ 64์ง๋ฒ์ผ๋ก ๋ํ๋ธ ๊ฒ)๋ก ์ธ์ฝ๋ฉํ ์ด์ง ๋ฐ์ดํฐ๋ฅผ ์๋ฒ ๋ํ ์ ์๋ค(๋ฌผ๋ก ์ผ๋ฐ ํ ์คํธ๋ base64๋ก ์ธ์ฝ๋ฉํ ์ ์๋ค). ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ base64๋ก ์ธ์ฝ๋ฉํด์ ํ ์คํธ๋ก ๋ค๋ฃฐ ์ ์์ง๋ง ์๋ณธ๋ณด๋ค ์ฝ 33% ์ ๋ ํฌ๊ธฐ๊ฐ ๋์ด๋๋ ๋จ์ ์ด ์๋ค. ๋ฐ๋ผ์ ํฐ ์ด๋ฏธ์ง์ ์ฌ์ฉํ๊ธฐ์ ์ ํฉํ์ง ์๋ค.
// ์ด๋ฏธ์ง๋ฅผ Data URI๋ก ๋ณํํ๋ฉด ์๋์ฒ๋ผ ๋์จ๋ค
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA////sViHsVR/rSQDsVyLRwD++ffuUBL//Pv97+vrT...';
์ฝ๋ ์ฐธ๊ณ MDN
Hello World!
๋ฌธ์์ด์ text/plain ๋ฐ์ดํฐ โผ
data:,Hello%2C%20World!
Hello World!
๋ฌธ์์ด์ base64 ์ธ์ฝ๋ฉ ๋ฒ์ โผ
data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
<h1>Hello, World!</h1>
์ธ HTML ๋ฌธ์ โผ
data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E
์๋ฐ์คํฌ๋ฆฝํธ alert ์ฐฝ์ ์คํํ๋ HTML ๋ฌธ์ โผ
data:text/html,<script>alert('hi');</script>
๋ฐฉ๋ฒ 2 — CSS ํ์ผ์ ์ปค์คํ ํด๋์ค ์ ์
๐ก NextJS(SSG / SSR)์์ ์ํฉ์ ๋ฐ๋ผ ์๋ ๋ฐฉ๋ฒ ์๋ ์๋ ์์ผ๋ ์ฐธ๊ณ .
CSS ํ์ผ์์ ์ปค์คํ
ํด๋์ค๋ฅผ ๋ง๋ ํ background-image
์์ฑ url()
ํจ์์ svg ํ์ผ ๊ฒฝ๋ก๋ฅผ ๋ช
์ํ๋ค. ๊ทธ๋ฐ ํ ํ์ํ ์ปดํฌ๋ํธ์์ class๋ฅผ ์ถ๊ฐํด์ ์ฌ์ฉํ๋ฉด ๋๋ค.
.bg-arrow-down {
background-image: url('../assets/image/arrow-down.svg') no-repeat right center; /* no-repeat 100% 50% */
}
// ์ปดํฌ๋ํธ return๋ฌธ
<select className="bg-arrow-down pr-4">...</select>;
๋ ํผ๋ฐ์ค
- Base 64 ๊ฐ๋จ ์ ๋ฆฌํ๊ธฐ
- Data URIs - HTTP | MDN
- ReactDOMServer - React
- [React] Create-react-app ํ๋ก์ ํธ์์ ์ด๋ฏธ์ง ๊ฒฝ๋ก๋ฅผ ์ค์ ํ๋ 4๊ฐ์ง ๋ฐฉ๋ฒ
- 09: SVG with Data URIs | CSS-Tricks
๊ธ ์์ ์ฌํญ์ ๋ ธ์ ํ์ด์ง์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ฉ๋๋ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์
'๐ช Programming' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[DevTools] ๊ตฌ๊ธ ํฌ๋กฌ ๋์์ธ ๋ชจ๋ (Design Mode)
[DevTools] ๊ตฌ๊ธ ํฌ๋กฌ ๋์์ธ ๋ชจ๋ (Design Mode)
2024.05.10 -
[JS] Lodash Import ์ฉ๋ ์ค์ด๊ธฐ ํ
[JS] Lodash Import ์ฉ๋ ์ค์ด๊ธฐ ํ
2024.05.10 -
[JS] toISOString() ๋ฉ์๋ ์คํ์ ๊ต์ ํ๊ธฐ (UTC ์๊ฐ๋ ๋ณ๊ฒฝ)
[JS] toISOString() ๋ฉ์๋ ์คํ์ ๊ต์ ํ๊ธฐ (UTC ์๊ฐ๋ ๋ณ๊ฒฝ)
2024.05.09 -
[Git] PR / Commit ๋ฉ์์ง ํค์๋๋ก ์ด์ ์ฐ๋ ๋ฐ ์ข ๋ฃํ๊ธฐ
[Git] PR / Commit ๋ฉ์์ง ํค์๋๋ก ์ด์ ์ฐ๋ ๋ฐ ์ข ๋ฃํ๊ธฐ
2024.05.09