๐ Shadow DOM์ผ๋ก ์คํ์ผ ์บก์ํํ๊ธฐ: ์น ๊ฐ๋ฐ์ ์จ์ ๋ณด์ ๐

์๋ ํ์ธ์, ๊ฐ๋ฐ์ ์ฌ๋ฌ๋ถ! ์ค๋์ ์ ๋ง ํฅ๋ฏธ์ง์งํ ์ฃผ์ ๋ก ์ฐพ์์์ด์. ๋ฐ๋ก Shadow DOM์ ํ์ฉํ ์คํ์ผ ์บก์ํ์ ๋ํด ๊น์ด ํํค์ณ๋ณผ ๊ฑฐ์์. ์ด๊ฑฐ ์์ ๋๋ฐ ์ฃผ์ ์๋์์? ใ ใ ใ ๐
์ฌ๋ฌ๋ถ, ํน์ ์น ๊ฐ๋ฐํ๋ค๊ฐ ์คํ์ผ์ด ์์ผ์ ๋จธ๋ฆฌ ์ํ ๋ ์ ์์ผ์ ๊ฐ์? CSS ํด๋์ค๋ช ์ง๋๋ผ ๊ณ ๋ฏผํ๋ค๊ฐ ๋ฐค์์ ์ ์์? ๊ทธ๋ ๋ค๋ฉด ์ค๋ ๋ฐฐ์ธ Shadow DOM์ด ์ฌ๋ฌ๋ถ์ ๊ตฌ์์๊ฐ ๋ ๊ฑฐ์์! ๐ผ
๐ TIP: Shadow DOM์ ์น ์ปดํฌ๋ํธ์ ํต์ฌ ๊ธฐ์ ์ค ํ๋๋ก, HTML, CSS, JavaScript๋ฅผ ์บก์ํํ์ฌ ์ธ๋ถ์ ๊ฒฉ๋ฆฌ๋ ๋ ๋ฆฝ์ ์ธ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๊ฒ ํด์ค๋๋ค.
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก Shadow DOM์ ์ธ๊ณ๋ก ๋ค์ด๊ฐ๋ณผ๊น์? ์ค๋น๋์ จ๋์? ๊ทธ๋ผ ๊ณ ๊ณ ์ฝ~ ๐
๐ Shadow DOM์ด ๋ญ๊ธธ๋ ์ด๋ ๊ฒ ํซํ ๊ฑฐ์ผ?
Shadow DOM์ด๋ผ... ์ด๋ฆ๋ถํฐ ์ข ๋ฏธ์คํฐ๋ฆฌํ์ง ์๋์? ใ ใ ใ ๋ง์น ์ด๋ ์์ ์จ์ด์๋ ๋น๋ฐ ๊ฐ์์. ๊ทผ๋ฐ ์ค์ ๋ก๋ ๊ทธ๋์! Shadow DOM์ ์น ํ์ด์ง์ ๋ฉ์ธ DOM๊ณผ๋ ๋ณ๊ฐ๋ก ์กด์ฌํ๋ ์จ๊ฒจ์ง DOM ํธ๋ฆฌ๋ฅผ ๋ง๋ค์ด๋ด๊ฑฐ๋ ์. ๐ฒ
์ฝ๊ฒ ๋งํด์, Shadow DOM์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ์ปดํฌ๋ํธ๋ฅผ ์ธ๋ถ ์ธ๊ณ๋ก๋ถํฐ ๋ณดํธํด์ฃผ๋ ๋ฐฉํจ ๊ฐ์ ๊ฑฐ์์. ์ด ๋ฐฉํจ ๋๋ถ์ ์ฐ๋ฆฌ์ ์์คํ ์คํ์ผ๊ณผ ๋งํฌ์ ์ด ์ธ๋ถ์ CSS์ ์ํฅ์ ๋ฐ์ง ์๊ณ ์์ ํ๊ฒ ๋ณดํธ๋ฐ์ ์ ์๋ต๋๋ค.
๐ก ์์ธ์ ์ก: Shadow DOM์ด๋ผ๋ ์ด๋ฆ์ ์ด DOM์ด ๋ฉ์ธ ๋ฌธ์ DOM์ '๊ทธ๋ฆผ์(Shadow)'์ฒ๋ผ ๋ถ์ด์๋ค๋ ๊ฐ๋ ์์ ์์ด์. ๋ฉ์ง์ง ์๋์?
๊ทธ๋ผ ์ด์ Shadow DOM์ด ์ด๋ป๊ฒ ์๊ฒผ๋์ง ํ๋ฒ ๋ค์ฌ๋ค๋ณผ๊น์? ์๋ SVG๋ก ๊ฐ๋จํ๊ฒ ํํํด๋ดค์ด์!
์ฐ์, ๊ทธ๋ฆผ์ผ๋ก ๋ณด๋๊น ๋ ์ดํด๊ฐ ์ ๋์ฃ ? Shadow DOM์ ๋ง์น ๋น๋ฐ ์์ ๊ฐ์์. ์ธ๋ถ์ ์คํ์ผ ๊ณต๊ฒฉ(?)์ผ๋ก๋ถํฐ ์ฐ๋ฆฌ์ ์ปดํฌ๋ํธ๋ฅผ ์์ ํ๊ฒ ์ง์ผ์ฃผ๋ ๊ฑฐ์ฃ . ๐ฎโโ๏ธ
์ด๋ ๊ฒ Shadow DOM์ ์ฌ์ฉํ๋ฉด, ์ฐ๋ฆฌ๊ฐ ๋ง๋ ์ปดํฌ๋ํธ์ ์คํ์ผ์ด ๋ค๋ฅธ ์์๋ค๊ณผ ์ถฉ๋ํ ๊ฑฑ์ ์์ด ๋ ๋ฆฝ์ ์ผ๋ก ๋์ํ ์ ์์ด์. ์ด๊ฒ ๋ฐ๋ก ์คํ์ผ ์บก์ํ์ ํต์ฌ์ด์์!
๊ทธ๋ผ ์ด์ Shadow DOM์ ์ด๋ป๊ฒ ๋ง๋ค๊ณ ์ฌ์ฉํ๋์ง ์์ธํ ์์๋ณผ๊น์? ์ฌ๋ฅ๋ท์์ ๋ฐฐ์ด ์ง์์ ํ์ฉํด์ ์ค์ ๋ก ์ ์ฉํด๋ณด๋ฉด ๋ ์ฌ๋ฐ์ ๊ฑฐ์์! ๐
๐ ๏ธ Shadow DOM ๋ง๋ค๊ธฐ: ์ด๋ณด์๋ ํ ์ ์์ด์!
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก Shadow DOM์ ๋ง๋ค์ด๋ณผ ๊ฑฐ์์. ๊ฑฑ์ ๋ง์ธ์, ์๊ฐ๋ณด๋ค ์ด๋ ต์ง ์๋ต๋๋ค! ๐ค
๋จผ์ , Shadow DOM์ ๋ง๋ค๊ธฐ ์ํด์๋ Shadow Host๋ผ๋ ๊ฒ์ด ํ์ํด์. ์ด๊ฑด ๊ทธ๋ฅ ์ผ๋ฐ์ ์ธ HTML ์์์์. ์๋ฅผ ๋ค์ด ์ด๋ ๊ฒ์:
<div id="shadow-host"></div>
์ด์ ์ด Shadow Host์ Shadow DOM์ ๋ถ์ฌ๋ณผ ๊ฑฐ์์. JavaScript๋ฅผ ์ฌ์ฉํด์ ์ด๋ ๊ฒ ํ ์ ์์ด์:
const shadowHost = document.getElementById('shadow-host');
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
์ฐ์! ์ด๋ ๊ฒ ํ๋ฉด Shadow DOM์ด ์์ฑ๋์์ด์. attachShadow ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ Shadow Root๋ฅผ ๋ง๋ ๊ฑฐ์์. ์ฌ๊ธฐ์ {mode: 'open'}์ ๋ญ๊น์? ์ด๊ฑด ์ธ๋ถ์์ JavaScript๋ฅผ ํตํด Shadow DOM์ ์ ๊ทผํ ์ ์๊ฒ ํด์ฃผ๋ ์ต์ ์ด์์.
๐จ ์ฃผ์: mode๋ฅผ 'closed'๋ก ์ค์ ํ๋ฉด ์ธ๋ถ์์ Shadow DOM์ ์ ๊ทผํ ์ ์์ด์. ๋ณด์์ด ์ค์ํ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋ฉด ์ข๊ฒ ์ฃ ?
์ด์ Shadow DOM ์์ ๋ด์ฉ์ ๋ฃ์ด๋ณผ๊น์? ์ด๋ ๊ฒ ํ ์ ์์ด์:
shadowRoot.innerHTML = `
<style>
p { color: blue; }
</style>
<p>์๋
ํ์ธ์, ์ ๋ Shadow DOM ์์ ์์ด์!</p>
`;
์ง์~ ๐ ์ด์ ์ฐ๋ฆฌ๋ง์ Shadow DOM์ด ์์ฑ๋์์ด์! ์ด Shadow DOM ์์ ์๋ p ํ๊ทธ๋ ํ๋์์ผ๋ก ํ์๋ ๊ฑฐ์์. ๊ทธ๋ฆฌ๊ณ ์ด ์คํ์ผ์ Shadow DOM ๋ฐ์ ๋ค๋ฅธ p ํ๊ทธ์๋ ์ ํ ์ํฅ์ ์ฃผ์ง ์์์. ์์ ๋๋ฐ ์๋์์? ใ ใ ใ
์ด๋ ๊ฒ ๋ง๋ Shadow DOM์ ์๊ฐํํด๋ณด๋ฉด ์ด๋ฐ ๋ชจ์ต์ด์์:
์ด ๊ทธ๋ฆผ์ ๋ณด๋ฉด Shadow DOM์ ๊ตฌ์กฐ๊ฐ ํ๋์ ๋ค์ด์ค์ฃ ? Shadow Host ์์ Shadow Root๊ฐ ์๊ณ , ๊ทธ ์์ ์ฐ๋ฆฌ๊ฐ ์ ์ํ ์คํ์ผ๊ณผ ๋ด์ฉ์ด ๋ค์ด์์ด์. ์ด๋ ๊ฒ ์บก์ํ๋ ๊ตฌ์กฐ ๋๋ถ์ ์ธ๋ถ ์คํ์ผ์ ์ํฅ์ ๋ฐ์ง ์๋ ๊ฑฐ์์!
Shadow DOM์ ์ด์ฉํ๋ฉด ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์น ์ปดํฌ๋ํธ๋ฅผ ์ฝ๊ฒ ๋ง๋ค ์ ์์ด์. ์๋ฅผ ๋ค์ด, ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์ ํ๋กํ ์นด๋๋ฅผ ๋ง๋ ๋ค๊ณ ์๊ฐํด๋ณผ๊น์? Shadow DOM์ ์ด์ฉํ๋ฉด ํ๋กํ ์นด๋์ ์คํ์ผ๊ณผ ๊ตฌ์กฐ๋ฅผ ์๋ฒฝํ๊ฒ ์บก์ํํ ์ ์์ด์. ๊ทธ๋ฌ๋ฉด ์ฌ์ดํธ์ ๋ค๋ฅธ ๋ถ๋ถ์์ ์ด๋ค ์คํ์ผ์ ์ฌ์ฉํ๋ ํ๋กํ ์นด๋๋ ํญ์ ์ผ๊ด๋ ๋ชจ์ต์ ์ ์งํ ์ ์๊ฒ ์ฃ !
๐ก Pro Tip: Shadow DOM์ ์ฌ์ฉํ ๋๋ ์ฑ๋ฅ์๋ ์ ๊ฒฝ ์จ์ผ ํด์. ๋๋ฌด ๋ง์ Shadow DOM์ ์ฌ์ฉํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ฆ๊ฐํ ์ ์์ผ๋ ์ ์ ํ ์ฌ์ฉํ๋ ๊ฒ ์ข์์!
์ฌ๊ธฐ๊น์ง Shadow DOM์ ๋ง๋๋ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ์ ์์๋ดค์ด์. ์ด์ Shadow DOM์ ํ์ฉํด์ ์ด๋ป๊ฒ ์คํ์ผ์ ์บก์ํํ๋์ง ๋ ์์ธํ ์์๋ณผ๊น์? ๐ค
๐จ Shadow DOM์ผ๋ก ์คํ์ผ ์บก์ํํ๊ธฐ: CSS์ ํ๋ช !
์, ์ด์ Shadow DOM์ ์ด์ฉํด์ ์ด๋ป๊ฒ ์คํ์ผ์ ์บก์ํํ๋์ง ์์ธํ ์์๋ณผ ๊ฑฐ์์. ์ด๊ฑด ์ ๋ง CSS ๊ฐ๋ฐ์ ํ๋ช ์ด๋ผ๊ณ ํ ์ ์์ด์! ๐
๋จผ์ , ์คํ์ผ ์บก์ํ๊ฐ ์ ์ค์ํ์ง ์๊ฐํด๋ณผ๊น์? ๋๊ท๋ชจ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ๋, CSS ํด๋์ค ์ด๋ฆ์ด ์ถฉ๋ํ๊ฑฐ๋ ์๋์น ์๊ฒ ๋ค๋ฅธ ์์์ ์ํฅ์ ๋ฏธ์น๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์. ์ด๋ฐ ๋ฌธ์ ๋ฅผ CSS ๋์๋ผ๊ณ ํ๋๋ฐ, Shadow DOM์ ์ฌ์ฉํ๋ฉด ์ด ๋ฌธ์ ๋ฅผ ์๋ฒฝํ๊ฒ ํด๊ฒฐํ ์ ์์ด์!
Shadow DOM ์์ ์ ์๋ ์คํ์ผ์ Shadow DOM ๋ฐ์ผ๋ก ์์ด๋๊ฐ์ง ์์์. ๋ํ ์ธ๋ถ์ ์คํ์ผ๋ Shadow DOM ์์ผ๋ก ๋ค์ด์ค์ง ๋ชปํด์. ์ด๊ฒ ๋ฐ๋ก ์คํ์ผ ์บก์ํ์ ํต์ฌ์ด์์!
๐ ๊ฟํ: Shadow DOM์ ์ฌ์ฉํ๋ฉด CSS ํด๋์ค ์ด๋ฆ์ ๊ณ ๋ฏผํ ํ์๊ฐ ์์ด์. Shadow DOM ์์์๋ ์ด๋ค ํด๋์ค ์ด๋ฆ์ ์ฌ์ฉํด๋ ์ธ๋ถ์ ์ถฉ๋ํ ์ผ์ด ์๊ฑฐ๋ ์!
์, ๊ทธ๋ผ ์ค์ ๋ก ์ด๋ป๊ฒ ์คํ์ผ์ ์บก์ํํ๋์ง ์์ ๋ฅผ ํตํด ์์๋ณผ๊น์?
const shadowHost = document.getElementById('shadow-host');
const shadowRoot = shadowHost.attachShadow({mode: 'open'});
shadowRoot.innerHTML = `
<style>
.container {
background-color: #f0f0f0;
padding: 20px;
border-radius: 8px;
}
.title {
color: #333;
font-size: 24px;
}
.content {
color: #666;
font-size: 16px;
}
</style>
<div class="container">
<h2 class="title">์๋
ํ์ธ์, Shadow DOM!</h2>
<p class="content">์ด ์คํ์ผ์ ์บก์ํ๋์ด ์์ด์.</p>
</div>
`;
์ฐ์, ์ด๋ ๊ฒ ํ๋ฉด ์๋ฒฝํ๊ฒ ์บก์ํ๋ ์ปดํฌ๋ํธ๊ฐ ๋ง๋ค์ด์ ธ์! ๐ ์ด Shadow DOM ์์ ์ ์๋ .container, .title, .content ํด๋์ค๋ ์ธ๋ถ DOM์ ์๋ ๊ฐ์ ์ด๋ฆ์ ํด๋์ค์ ์ ํ ์ถฉ๋ํ์ง ์์์.
์ด๊ฑธ ์๊ฐํํด๋ณด๋ฉด ์ด๋ฐ ๋๋์ด์์:
์ด ๊ทธ๋ฆผ์ ๋ณด๋ฉด Shadow DOM ์์ ์คํ์ผ์ด ์ด๋ป๊ฒ ์บก์ํ๋๋์ง ์ ๋ณด์ด์ฃ ? ์ธ๋ถ์์ ์๋ฌด๋ฆฌ ๊ฐ์ ํด๋์ค ์ด๋ฆ์ ์ฌ์ฉํด๋ Shadow DOM ์์ ์คํ์ผ์๋ ์ํฅ์ ์ค ์ ์์ด์. ์์ ์ฒ ๋ฒฝ ๋ฐฉ์ด์์! ๐ช
์ด๋ฐ ๋ฐฉ์์ผ๋ก ์คํ์ผ์ ์บก์ํํ๋ฉด ์ ๋ง ๋ง์ ์ด์ ์ด ์์ด์:
- ๐ฏ ํด๋์ค ์ด๋ฆ ์ถฉ๋ ๋ฐฉ์ง: ๋ ์ด์ BEM์ด๋ ๋ค๋ฅธ ๋ณต์กํ ๋ค์ด๋ฐ ๊ท์น์ ์ฌ์ฉํ ํ์๊ฐ ์์ด์.
- ๐ ์คํ์ผ ๊ฒฉ๋ฆฌ: ์ปดํฌ๋ํธ์ ์คํ์ผ์ด ๋ค๋ฅธ ์์์ ์ํฅ์ ์ฃผ์ง ์์์.
- โป๏ธ ์ฌ์ฌ์ฉ์ฑ ํฅ์: ์๋ฒฝํ๊ฒ ์บก์ํ๋ ์ปดํฌ๋ํธ๋ ์ด๋์์๋ ์์ ํ๊ฒ ์ฌ์ฌ์ฉํ ์ ์์ด์.
- ๐งน ์ฝ๋ ์ ๋ฆฌ: ์ ์ญ ์ค์ฝํ๋ฅผ ๋๋ฝํ์ง ์๊ณ ๊น๋ํ๊ฒ ์คํ์ผ์ ๊ด๋ฆฌํ ์ ์์ด์.
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์ ๊ฐ๋ฐํ ๋ ์ด๋ฐ ์คํ์ผ ์บก์ํ ๊ธฐ์ ์ ์ฌ์ฉํ๋ฉด ์ ๋ง ํธ๋ฆฌํ ๊ฑฐ์์. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์ ํ๋กํ ์นด๋, ๋ฆฌ๋ทฐ ์ปดํฌ๋ํธ, ๊ฒฐ์ ํผ ๋ฑ ๋ค์ํ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ๋ฅผ Shadow DOM์ผ๋ก ๋ง๋ค ์ ์์ด์. ์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ดํธ์ ๋ค๋ฅธ ๋ถ๋ถ์ ์์ ํ๋๋ผ๋ ์ด ์ปดํฌ๋ํธ๋ค์ ํญ์ ์ผ๊ด๋ ๋ชจ์ต์ ์ ์งํ ์ ์์ฃ !
๐ก ์ฌ๋ฅ๋ท ๊ฐ๋ฐ์ Tip: Shadow DOM์ ์ฌ์ฉํ ๋๋ ์ฑ๋ฅ ์ต์ ํ์๋ ์ ๊ฒฝ ์จ์ผ ํด์. ๋๋ฌด ๋ง์ Shadow DOM์ ์ฌ์ฉํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ฆ๊ฐํ ์ ์์ผ๋, ๊ผญ ํ์ํ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์!
์, ์ฌ๊ธฐ๊น์ง Shadow DOM์ ์ด์ฉํ ์คํ์ผ ์บก์ํ์ ๋ํด ์์๋ดค์ด์. ์ด์ Shadow DOM์ ์ฅ๋จ์ ์ ๋ํด ๋ ์์ธํ ์์๋ณผ๊น์? ๐ค
๐๐ Shadow DOM์ ์ฅ๋จ์ : ์๋ ์ ๊ฒ?
Shadow DOM์ ์ ๋ง ๊ฐ๋ ฅํ ๊ธฐ์ ์ด์ง๋ง, ๋ชจ๋ ๊ธฐ์ ์ด ๊ทธ๋ ๋ฏ ์ฅ๋จ์ ์ด ์์ด์. ์ด์ Shadow DOM์ ์ฅ๋จ์ ์ ์์ธํ ์ดํด๋ณผ๊ฒ์. ์ด๊ฑธ ์๋ฉด ์ธ์ Shadow DOM์ ์ฌ์ฉํด์ผ ํ ์ง, ์ธ์ ๋ ์ฌ์ฉํ์ง ๋ง์์ผ ํ ์ง ํ๋จํ ์ ์์ ๊ฑฐ์์!
๐ Shadow DOM์ ์ฅ์
- ์๋ฒฝํ ์คํ์ผ ๊ฒฉ๋ฆฌ: ์ด๊ฑด ์ ๋ง ๋๋ฐ์ด์์! ์ธ๋ถ ์คํ์ผ์ ์ํฅ์ ์ ํ ๋ฐ์ง ์์์. CSS ์ง์ฅ์์ ๋ฒ์ด๋ ์ ์์ด์! ๐
- ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ์ฑ ํฅ์: ํ ๋ฒ ๋ง๋ค์ด ๋์ผ๋ฉด ์ด๋์๋ ์ธ ์ ์์ด์. ์ฌ๋ฅ๋ท์์ ์ฌ๋ฌ ํ์ด์ง์ ๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํด์ผ ํ ๋ ์์ ๊ฟ์ด๊ฒ ์ฃ ?
- ์ฝ๋ ๊ตฌ์กฐํ: HTML, CSS, JavaScript๋ฅผ ํ๋์ ๋จ์๋ก ๋ฌถ์ ์ ์์ด์. ์ฝ๋๊ฐ ํจ์ฌ ๊น๋ํด์ ธ์!
- ์ฑ๋ฅ ์ต์ ํ: ๋ธ๋ผ์ฐ์ ๊ฐ Shadow DOM์ ๋ณ๋๋ก ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์, ๋ ๋๋ง ์ฑ๋ฅ์ด ํฅ์๋ ์ ์์ด์.
- ๋ณด์ ๊ฐํ: Shadow DOM ๋ด๋ถ์ ์์๋ ์ธ๋ถ์์ ์ ๊ทผํ๊ธฐ ์ด๋ ค์์. XSS ๊ณต๊ฒฉ ๊ฐ์ ๋ณด์ ์ํ์ ์ค์ผ ์ ์์ฃ .
์ฐ์, ์ฅ์ ์ด ์ ๋ง ๋ง์ฃ ? ๊ทผ๋ฐ ์ ๊น, ๋จ์ ๋ ์์ ๊ฑฐ์์. ํ๋ฒ ์ดํด๋ณผ๊น์?
๐ Shadow DOM์ ๋จ์
- ํ์ต ๊ณก์ : ์ฒ์ ์ ํ๋ฉด ์ข ์ด๋ ค์ธ ์ ์์ด์. ๊ธฐ์กด DOM๊ณผ๋ ๋ค๋ฅธ ๊ฐ๋ ์ด๋ผ ์ ์์ด ํ์ํด์.
- ๋๋ฒ๊น ์ ์ด๋ ค์: Shadow DOM ๋ด๋ถ๋ฅผ ๋๋ฒ๊น ํ๋ ๊ฒ ์กฐ๊ธ ๊น๋ค๋ก์ธ ์ ์์ด์. ๊ฐ๋ฐ์ ๋๊ตฌ์์ Shadow DOM์ ํ์ธํ๋ ๋ฐฉ๋ฒ์ ๋ฐ๋ก ์์์ผ ํด์.
- ์ธ๋ถ ์คํ์ผ ์ ์ฉ์ ์ด๋ ค์: ๋๋ก๋ ์ธ๋ถ์์ Shadow DOM ๋ด๋ถ ์คํ์ผ์ ๋ณ๊ฒฝํ๊ณ ์ถ์ ๋๊ฐ ์๋๋ฐ, ์ด๊ฒ ์ฝ์ง ์์์.
- ๋ธ๋ผ์ฐ์ ์ง์: ๋๋ถ๋ถ์ ์ต์ ๋ธ๋ผ์ฐ์ ๋ ์ง์ํ์ง๋ง, ์ผ๋ถ ๊ตฌํ ๋ธ๋ผ์ฐ์ ์์๋ ์๋ํ์ง ์์ ์ ์์ด์.
- SEO ๋ฌธ์ : ๊ฒ์ ์์ง์ด Shadow DOM ๋ด๋ถ์ ์ฝํ ์ธ ๋ฅผ ์ ๋๋ก ์ธ์ํ์ง ๋ชปํ ์ ์์ด์.
์... ๋จ์ ๋ ๋ง๋ง์น ์๋ค์. ๊ทธ๋๋ ๊ฑฑ์ ๋ง์ธ์! ์ด๋ฐ ๋จ์ ๋ค์ ๋๋ถ๋ถ ์ ์ ํ ์ฌ์ฉ๊ณผ ์ถ๊ฐ์ ์ธ ๊ธฐ์ ๋ก ๊ทน๋ณตํ ์ ์์ด์. ๐
๐ค ์๊ฐํด๋ณด๊ธฐ: ์ฌ๋ฅ๋ท์์ Shadow DOM์ ์ฌ์ฉํ๋ค๋ฉด ์ด๋ค ์ฅ์ ์ ๊ฐ์ฅ ํฌ๊ฒ ๋๋ฆด ์ ์์๊น์? ๋ฐ๋๋ก, ์ด๋ค ๋จ์ ์ ์ฃผ์ํด์ผ ํ ๊น์?
์, ์ด์ Shadow DOM์ ์ฅ๋จ์ ์ ์ ์๊ฒ ์ด์. ์ด์ Shadow DOM์ ์ฅ๋จ์ ์ ์ ์ดํดํ์ จ์ ๊ฑฐ์์. ๊ทธ๋ผ ์ด์ ์ค์ ๋ก Shadow DOM์ ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง, ํนํ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ์ด๋ป๊ฒ ์ฌ์ฉํ ์ ์์์ง ์ดํด๋ณผ๊น์? ๐
๐ Shadow DOM ์ค์ ํ์ฉ: ์ฌ๋ฅ๋ท์์์ ์์ฉ
์, ์ด์ ์ฌ๋ฅ๋ท์์ Shadow DOM์ ์ด๋ป๊ฒ ํ์ฉํ ์ ์์์ง ๊ตฌ์ฒด์ ์ธ ์์๋ฅผ ํตํด ์์๋ณผ๊ฒ์. ์ฌ๋ฅ๋ท์ ๋ค์ํ ์ฌ์ฉ์๋ค์ ์ฌ๋ฅ์ ๊ฑฐ๋ํ๋ ํ๋ซํผ์ด๋๊น, ์ฌ๋ฌ ๊ฐ์ง ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ๊ฐ ํ์ํ ๊ฑฐ์์. ๊ทธ์ค์์ '์ฌ์ฉ์ ํ๋กํ ์นด๋'๋ฅผ Shadow DOM์ผ๋ก ๋ง๋ค์ด๋ณผ๊น์? ๐
class UserProfileCard extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
.card {
background-color: #f0f0f0;
border-radius: 8px;
padding: 16px;
width: 300px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.avatar {
width: 100px;
height: 100px;
border-radius: 50%;
margin-bottom: 10px;
}
.name {
font-size: 24px;
color: #333;
margin-bottom: 5px;
}
.skill {
font-size: 16px;
color: #666;
}
</style>
<div class="card">
<img class="avatar" src="${this.getAttribute('avatar')}" alt="User Avatar">
<h2 class="name">${this.getAttribute('name')}</h2>
<p class="skill">${this.getAttribute('skill')}</p>
</div>
`;
}
}
customElements.define('user-profile-card', UserProfileCard);
์ฐ์! ์ด๋ ๊ฒ ํ๋ฉด ์์ ํ ์บก์ํ๋ ์ฌ์ฉ์ ํ๋กํ ์นด๋ ์ปดํฌ๋ํธ๊ฐ ๋ง๋ค์ด์ ธ์. ์ด์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ๋ฅ๋ท์ ์ด๋ ํ์ด์ง์์๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ด์:
<user-profile-card
avatar="https://example.com/avatar.jpg"
name="๊น์ฌ๋ฅ"
skill="์น ๊ฐ๋ฐ"></user-profile-card>
์ด๋ ๊ฒ ๋ง๋ ์ปดํฌ๋ํธ๋ ์ฌ๋ฅ๋ท์ ๋ค๋ฅธ ์คํ์ผ์ ์ํฅ์ ๋ฐ์ง ์๊ณ , ํญ์ ์ผ๊ด๋ ๋ชจ์ต์ ์ ์งํ ์ ์์ด์. ์ ๋ง ํธ๋ฆฌํ์ฃ ? ๐
๐ก Pro Tip: Shadow DOM์ ์ฌ์ฉํ ๋๋ ์ ๊ทผ์ฑ(accessibility)์๋ ์ ๊ฒฝ ์จ์ผ ํด์. Screen reader๊ฐ Shadow DOM ๋ด๋ถ์ ์ฝํ ์ธ ๋ฅผ ์ ๋๋ก ์ฝ์ ์ ์๋๋ก ์ ์ ํ ARIA ์์ฑ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์!
์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ฌ๋ฅ๋ท์ ๋ค์ํ ์ปดํฌ๋ํธ๋ฅผ Shadow DOM์ผ๋ก ๋ง๋ค ์ ์์ด์. ์๋ฅผ ๋ค๋ฉด:
- ๐ ๋ฆฌ๋ทฐ ์ปดํฌ๋ํธ: ์ฌ์ฉ์๋ค์ ๋ฆฌ๋ทฐ๋ฅผ ํ์ํ๋ ์ปดํฌ๋ํธ
- ๐ฐ ๊ฐ๊ฒฉ ํ์ ์ปดํฌ๋ํธ: ์ฌ๋ฅ์ ๊ฐ๊ฒฉ์ ํ์ํ๋ ์ปดํฌ๋ํธ
- ๐ ์ผ์ ์ ํ ์ปดํฌ๋ํธ: ์ฌ๋ฅ ๊ฑฐ๋ ์ผ์ ์ ์ ํํ๋ ์ปดํฌ๋ํธ
- ๐ ์ ์ ๋ฑ์ง ์ปดํฌ๋ํธ: ์ฌ์ฉ์์ ์ ์ ์ ํ์ํ๋ ๋ฑ์ง ์ปดํฌ๋ํธ
์ด๋ ๊ฒ Shadow DOM์ ํ์ฉํ๋ฉด ์ฌ๋ฅ๋ท์ UI๋ฅผ ๋์ฑ ๋ชจ๋ํํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค ์ ์์ด์. ๋ํ ๊ฐ ์ปดํฌ๋ํธ์ ์คํ์ผ์ด ์๋ฒฝํ๊ฒ ์บก์ํ๋์ด ์์ด์, ์ฌ์ดํธ์ ์ ์ฒด์ ์ธ ๋์์ธ์ ๋ณ๊ฒฝํ๋๋ผ๋ ์ด ์ปดํฌ๋ํธ๋ค์ ์ํฅ์ ๋ฐ์ง ์์์. ์ ๋ง ํธ๋ฆฌํ์ฃ ? ๐
ํ์ง๋ง ์ฃผ์ํ ์ ๋ ์์ด์. Shadow DOM์ ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ํ์ด์ง์ ์ ์ฒด์ ์ธ ์ผ๊ด์ฑ์ ํด์น ์ ์์ด์. ๋ํ, SEO์๋ ์ํฅ์ ์ค ์ ์์ผ๋ ์ฃผ์ํด์ผ ํด์. ๊ทธ๋์ Shadow DOM์ ๊ผญ ํ์ํ ๊ฒฝ์ฐ์๋ง ์ ๋ณ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์.
์ด ๊ทธ๋ฆผ์ ๋ณด๋ฉด ์ฌ๋ฅ๋ท ํ์ด์ง์์ Shadow DOM์ผ๋ก ๋ง๋ ์ปดํฌ๋ํธ๋ค์ด ์ด๋ป๊ฒ ๋ ๋ฆฝ์ ์ผ๋ก ์กด์ฌํ๋์ง ํ๋์ ๋ณผ ์ ์์ด์. ๊ฐ ์ปดํฌ๋ํธ๋ ์์ฒด์ ์ธ ์คํ์ผ์ ๊ฐ์ง๊ณ ์์ด์ ๋ฉ์ธ ํ์ด์ง์ ์คํ์ผ ๋ณ๊ฒฝ์ ์ํฅ์ ๋ฐ์ง ์์์. ๋ฉ์ง์ฃ ? ๐
์, ์ฌ๊ธฐ๊น์ง Shadow DOM์ ์ค์ ๋ก ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง ์์๋ดค์ด์. ์ด์ Shadow DOM์ ๋ํด ๊ฝค ๋ง์ด ์๊ฒ ๋์ จ์ ๊ฒ ๊ฐ์์. ํ์ง๋ง ์์ง ๋ ์์๋ณผ ๊ฒ ์์ด์. Shadow DOM๊ณผ ๊ด๋ จ๋ ๋ช ๊ฐ์ง ๊ณ ๊ธ ๊ธฐ์ ์ ๋ํด ์ดํด๋ณผ๊น์? ๐
๐ฅ Shadow DOM ๊ณ ๊ธ ๊ธฐ์ : ํ ๋จ๊ณ ๋ ๋์๊ฐ๊ธฐ
์, ์ด์ Shadow DOM์ ๋ํด ๊ธฐ๋ณธ์ ์ธ ๊ฒ๋ค์ ๋ค ๋ฐฐ์ ์ด์. ํ์ง๋ง ๊ฐ๋ฐ์ ์ธ๊ณ๋ ๋์ด ์์ฃ ! ์ด์ Shadow DOM๊ณผ ๊ด๋ จ๋ ๋ช ๊ฐ์ง ๊ณ ๊ธ ๊ธฐ์ ์ ๋ํด ์์๋ณผ๊ฒ์. ์ด ๊ธฐ์ ๋ค์ ์ตํ๋ฉด ์ฌ๋ฌ๋ถ์ ์ง์ ํ Shadow DOM ๋ง์คํฐ๊ฐ ๋ ์ ์์ ๊ฑฐ์์! ๐
1. ์ฌ๋กฏ(Slot) ์ฌ์ฉํ๊ธฐ
์ฌ๋กฏ์ Shadow DOM ๋ด๋ถ์ ์ธ๋ถ ์ฝํ ์ธ ๋ฅผ ์ฝ์ ํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ด์์. ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์ ํ๋กํ ์นด๋๋ฅผ ๋ ์ ์ฐํ๊ฒ ๋ง๋ค์ด๋ณผ๊น์?
class UserProfileCard extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
.card { /* ์คํ์ผ์ ์ด์ ๊ณผ ๋์ผ */ }
</style>
<div class="card">
<slot name="avatar"><img src="default-avatar.jpg" alt="Default Avatar"></slot>
<h2 class="name"><slot name="name">์ด๋ฆ ์์</slot></h2>
<p class="skill"><slot name="skill">์คํฌ ์ ๋ณด ์์</slot></p>
<slot name="extra"></slot>
</div>
`;
}
}
customElements.define('user-profile-card', UserProfileCard);
์ด์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ด๋ ๊ฒ ์ฌ์ฉํ ์ ์์ด์:
<user-profile-card>
<img slot="avatar" src="kim.jpg" alt="๊น์ฌ๋ฅ์ ์๋ฐํ">
<span slot="name">๊น์ฌ๋ฅ</span>
<span slot="skill">์น ๊ฐ๋ฐ</span>
<p slot="extra">์ ๋ ์ด์ ์ ์ธ ๊ฐ๋ฐ์์
๋๋ค!</p>
</user-profile-card>
์ฐ์! ์ด๋ ๊ฒ ํ๋ฉด ์ปดํฌ๋ํธ๋ฅผ ํจ์ฌ ๋ ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์์ด์. ๐
2. CSS ์ปค์คํ ์์ฑ ํ์ฉํ๊ธฐ
CSS ์ปค์คํ ์์ฑ(๋ณ์)์ ์ฌ์ฉํ๋ฉด Shadow DOM ์ธ๋ถ์์ ๋ด๋ถ ์คํ์ผ์ ์ผ๋ถ ์ ์ดํ ์ ์์ด์. ์ฌ๋ฅ๋ท์ ํ ๋ง์ ๋ฐ๋ผ ํ๋กํ ์นด๋์ ์์์ ๋ณ๊ฒฝํ ์ ์๊ฒ ํด๋ณผ๊น์?
class UserProfileCard extends HTMLElement {
// ... ์ด์ ์ฝ๋ ์๋ต ...
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
.card {
background-color: var(--card-bg, #f0f0f0);
color: var(--card-color, #333);
/* ๋ค๋ฅธ ์คํ์ผ์ ์ด์ ๊ณผ ๋์ผ */
}
</style>
<!-- ์นด๋ ๋ด์ฉ์ ์ด์ ๊ณผ ๋์ผ -->
`;
}
}
customElements.define('user-profile-card', UserProfileCard);
์ด์ ์ธ๋ถ์์ ์ด๋ ๊ฒ ์คํ์ผ์ ๋ณ๊ฒฝํ ์ ์์ด์:
<style>
user-profile-card {
--card-bg: #e1f5fe;
--card-color: #01579b;
}
</style>
์ด๋ ๊ฒ ํ๋ฉด ์ฌ๋ฅ๋ท์ ๋ค์ํ ํ์ด์ง์์ ํ๋กํ ์นด๋์ ์คํ์ผ์ ์ ์ฐํ๊ฒ ์กฐ์ ํ ์ ์์ด์. ๋ฉ์ง์ฃ ? ๐
3. ์ด๋ฒคํธ ์ฌํ๊ฒํ (Retargeting) ์ดํดํ๊ธฐ
Shadow DOM ๋ด๋ถ์์ ๋ฐ์ํ ์ด๋ฒคํธ๋ Shadow ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋์ด๊ฐ ๋ ์ฌํ๊ฒํ ๋ผ์. ์ด๋ฅผ ์ดํดํ๊ณ ํ์ฉํ๋ฉด ์ปดํฌ๋ํธ์ ์ธ๋ถ ์ธ๊ณ์์ ์ํธ์์ฉ์ ๋ ์ ์ ์ดํ ์ ์์ด์.
class UserProfileCard extends HTMLElement {
// ... ์ด์ ์ฝ๋ ์๋ต ...
connectedCallback() {
// ... ์ด์ ์ฝ๋ ์๋ต ...
const nameElement = this.shadowRoot.querySelector('.name');
nameElement.addEventListener('click', (e) => {
const event = new CustomEvent('nameClicked', {
bubbles: true,
composed: true,
detail: { name: nameElement.textContent }
});
this.dispatchEvent(event);
});
}
}
// ์ฌ์ฉ ์:
document.querySelector('user-profile-card').addEventListener('nameClicked', (e) => {
console.log(`${e.detail.name}์ ํ๋กํ์ด ํด๋ฆญ๋์์ต๋๋ค!`);
});
์ด๋ ๊ฒ ํ๋ฉด Shadow DOM ๋ด๋ถ์ ์ด๋ฒคํธ๋ฅผ ์ธ๋ถ๋ก ์ ๋ฌํ ์ ์์ด์. ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์ ์ด๋ฆ์ ํด๋ฆญํ์ ๋ ํ๋กํ ํ์ด์ง๋ก ์ด๋ํ๋ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๊ฒ ์ฃ ?
๐ ๊ณ ๊ธ ํ: Shadow DOM์ ์ฌ์ฉํ ๋๋ ์ฑ๋ฅ ์ต์ ํ์๋ ์ ๊ฒฝ ์จ์ผ ํด์. ๋๋ฌด ๋ง์ Shadow DOM์ ์ฌ์ฉํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ฆ๊ฐํ ์ ์์ด์. ํ์ํ ๊ฒฝ์ฐ์๋ง ์ ๋ณ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์!
์, ์ฌ๊ธฐ๊น์ง Shadow DOM์ ๊ณ ๊ธ ๊ธฐ์ ๋ค์ ์ดํด๋ดค์ด์. ์ด ๊ธฐ์ ๋ค์ ์ ํ์ฉํ๋ฉด ์ฌ๋ฅ๋ท ๊ฐ์ ๋ณต์กํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ปดํฌ๋ํธ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ ์ฌ์ฌ์ฉํ ์ ์์ด์. ๐จโ๐ป๐ฉโ๐ป
Shadow DOM์ ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ๋ชจ๋ ์ํฉ์ ์ ํฉํ ๊ฒ์ ์๋์์. ํญ์ ํ๋ก์ ํธ์ ์๊ตฌ์ฌํญ๊ณผ ํน์ฑ์ ๊ณ ๋ คํด์ ์ ์ ํ ์ฌ์ฉํด์ผ ํด์. ๊ทธ๋ฆฌ๊ณ ์ ๊ทผ์ฑ๊ณผ SEO๋ ํญ์ ์ผ๋์ ๋์ด์ผ ํ๋ค๋ ๊ฑธ ์์ง ๋ง์ธ์!
์ฌ๊ธฐ๊น์ง Shadow DOM์ ๋ํด ์ ๋ง ๊น์ด ์๊ฒ ์์๋ดค์ด์. ์ด์ ์ฌ๋ฌ๋ถ์ Shadow DOM์ ์ง์ ํ ๋ง์คํฐ๊ฐ ๋์์ ๊ฑฐ์์! ๐ ์ด ์ง์์ ํ์ฉํด์ ์ฌ๋ฅ๋ท์ ๋์ฑ ๋ฉ์ง ํ๋ซํผ์ผ๋ก ๋ง๋ค์ด๋ณด๋ ๊ฑด ์ด๋จ๊น์? ํ์ดํ ! ๐ช๐
๐ Shadow DOM ์ค์ ํ์ฉ: ์ฌ๋ฅ๋ท์์์ ์์ฉ
์, ์ด์ ์ฌ๋ฅ๋ท์์ Shadow DOM์ ์ด๋ป๊ฒ ํ์ฉํ ์ ์์์ง ๊ตฌ์ฒด์ ์ธ ์์๋ฅผ ํตํด ์์๋ณผ๊ฒ์. ์ฌ๋ฅ๋ท์ ๋ค์ํ ์ฌ์ฉ์๋ค์ ์ฌ๋ฅ์ ๊ฑฐ๋ํ๋ ํ๋ซํผ์ด๋๊น, ์ฌ๋ฌ ๊ฐ์ง ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ๊ฐ ํ์ํ ๊ฑฐ์์. ๊ทธ์ค์์ '์ฌ์ฉ์ ํ๋กํ ์นด๋'๋ฅผ Shadow DOM์ผ๋ก ๋ง๋ค์ด๋ณผ๊น์? ๐
class UserProfileCard extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
.card {
background-color: #f0f0f0;
border-radius: 8px;
padding: 16px;
width: 300px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.avatar {
width: 100px;
height: 100px;
border-radius: 50%;
margin-bottom: 10px;
}
.name {
font-size: 24px;
color: #333;
margin-bottom: 5px;
}
.skill {
font-size: 16px;
color: #666;
}
</style>
<div class="card">
<img class="avatar" src="${this.getAttribute('avatar')}" alt="User Avatar">
<h2 class="name">${this.getAttribute('name')}</h2>
<p class="skill">${this.getAttribute('skill')}</p>
</div>
`;
}
}
customElements.define('user-profile-card', UserProfileCard);
์ฐ์! ์ด๋ ๊ฒ ํ๋ฉด ์์ ํ ์บก์ํ๋ ์ฌ์ฉ์ ํ๋กํ ์นด๋ ์ปดํฌ๋ํธ๊ฐ ๋ง๋ค์ด์ ธ์. ์ด์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ฌ๋ฅ๋ท์ ์ด๋ ํ์ด์ง์์๋ ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์ ์์ด์:
<user-profile-card
avatar="https://example.com/avatar.jpg"
name="๊น์ฌ๋ฅ"
skill="์น ๊ฐ๋ฐ"></user-profile-card>
์ด๋ ๊ฒ ๋ง๋ ์ปดํฌ๋ํธ๋ ์ฌ๋ฅ๋ท์ ๋ค๋ฅธ ์คํ์ผ์ ์ํฅ์ ๋ฐ์ง ์๊ณ , ํญ์ ์ผ๊ด๋ ๋ชจ์ต์ ์ ์งํ ์ ์์ด์. ์ ๋ง ํธ๋ฆฌํ์ฃ ? ๐
๐ก Pro Tip: Shadow DOM์ ์ฌ์ฉํ ๋๋ ์ ๊ทผ์ฑ(accessibility)์๋ ์ ๊ฒฝ ์จ์ผ ํด์. Screen reader๊ฐ Shadow DOM ๋ด๋ถ์ ์ฝํ ์ธ ๋ฅผ ์ ๋๋ก ์ฝ์ ์ ์๋๋ก ์ ์ ํ ARIA ์์ฑ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์!
์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ฌ๋ฅ๋ท์ ๋ค์ํ ์ปดํฌ๋ํธ๋ฅผ Shadow DOM์ผ๋ก ๋ง๋ค ์ ์์ด์. ์๋ฅผ ๋ค๋ฉด:
- ๐ ๋ฆฌ๋ทฐ ์ปดํฌ๋ํธ: ์ฌ์ฉ์๋ค์ ๋ฆฌ๋ทฐ๋ฅผ ํ์ํ๋ ์ปดํฌ๋ํธ
- ๐ฐ ๊ฐ๊ฒฉ ํ์ ์ปดํฌ๋ํธ: ์ฌ๋ฅ์ ๊ฐ๊ฒฉ์ ํ์ํ๋ ์ปดํฌ๋ํธ
- ๐ ์ผ์ ์ ํ ์ปดํฌ๋ํธ: ์ฌ๋ฅ ๊ฑฐ๋ ์ผ์ ์ ์ ํํ๋ ์ปดํฌ๋ํธ
- ๐ ์ ์ ๋ฑ์ง ์ปดํฌ๋ํธ: ์ฌ์ฉ์์ ์ ์ ์ ํ์ํ๋ ๋ฑ์ง ์ปดํฌ๋ํธ
์ด๋ ๊ฒ Shadow DOM์ ํ์ฉํ๋ฉด ์ฌ๋ฅ๋ท์ UI๋ฅผ ๋์ฑ ๋ชจ๋ํํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค ์ ์์ด์. ๋ํ ๊ฐ ์ปดํฌ๋ํธ์ ์คํ์ผ์ด ์๋ฒฝํ๊ฒ ์บก์ํ๋์ด ์์ด์, ์ฌ์ดํธ์ ์ ์ฒด์ ์ธ ๋์์ธ์ ๋ณ๊ฒฝํ๋๋ผ๋ ์ด ์ปดํฌ๋ํธ๋ค์ ์ํฅ์ ๋ฐ์ง ์์์. ์ ๋ง ํธ๋ฆฌํ์ฃ ? ๐
ํ์ง๋ง ์ฃผ์ํ ์ ๋ ์์ด์. Shadow DOM์ ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ํ์ด์ง์ ์ ์ฒด์ ์ธ ์ผ๊ด์ฑ์ ํด์น ์ ์์ด์. ๋ํ, SEO์๋ ์ํฅ์ ์ค ์ ์์ผ๋ ์ฃผ์ํด์ผ ํด์. ๊ทธ๋์ Shadow DOM์ ๊ผญ ํ์ํ ๊ฒฝ์ฐ์๋ง ์ ๋ณ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์.
์ด ๊ทธ๋ฆผ์ ๋ณด๋ฉด ์ฌ๋ฅ๋ท ํ์ด์ง์์ Shadow DOM์ผ๋ก ๋ง๋ ์ปดํฌ๋ํธ๋ค์ด ์ด๋ป๊ฒ ๋ ๋ฆฝ์ ์ผ๋ก ์กด์ฌํ๋์ง ํ๋์ ๋ณผ ์ ์์ด์. ๊ฐ ์ปดํฌ๋ํธ๋ ์์ฒด์ ์ธ ์คํ์ผ์ ๊ฐ์ง๊ณ ์์ด์ ๋ฉ์ธ ํ์ด์ง์ ์คํ์ผ ๋ณ๊ฒฝ์ ์ํฅ์ ๋ฐ์ง ์์์. ๋ฉ์ง์ฃ ? ๐
์, ์ฌ๊ธฐ๊น์ง Shadow DOM์ ์ค์ ๋ก ์ด๋ป๊ฒ ํ์ฉํ ์ ์๋์ง ์์๋ดค์ด์. ์ด์ Shadow DOM์ ๋ํด ๊ฝค ๋ง์ด ์๊ฒ ๋์ จ์ ๊ฒ ๊ฐ์์. ํ์ง๋ง ์์ง ๋ ์์๋ณผ ๊ฒ ์์ด์. Shadow DOM๊ณผ ๊ด๋ จ๋ ๋ช ๊ฐ์ง ๊ณ ๊ธ ๊ธฐ์ ์ ๋ํด ์ดํด๋ณผ๊น์? ๐
๐ฅ Shadow DOM ๊ณ ๊ธ ๊ธฐ์ : ํ ๋จ๊ณ ๋ ๋์๊ฐ๊ธฐ
์, ์ด์ Shadow DOM์ ๋ํด ๊ธฐ๋ณธ์ ์ธ ๊ฒ๋ค์ ๋ค ๋ฐฐ์ ์ด์. ํ์ง๋ง ๊ฐ๋ฐ์ ์ธ๊ณ๋ ๋์ด ์์ฃ ! ์ด์ Shadow DOM๊ณผ ๊ด๋ จ๋ ๋ช ๊ฐ์ง ๊ณ ๊ธ ๊ธฐ์ ์ ๋ํด ์์๋ณผ๊ฒ์. ์ด ๊ธฐ์ ๋ค์ ์ตํ๋ฉด ์ฌ๋ฌ๋ถ์ ์ง์ ํ Shadow DOM ๋ง์คํฐ๊ฐ ๋ ์ ์์ ๊ฑฐ์์! ๐
1. ์ฌ๋กฏ(Slot) ์ฌ์ฉํ๊ธฐ
์ฌ๋กฏ์ Shadow DOM ๋ด๋ถ์ ์ธ๋ถ ์ฝํ ์ธ ๋ฅผ ์ฝ์ ํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ด์์. ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์ ํ๋กํ ์นด๋๋ฅผ ๋ ์ ์ฐํ๊ฒ ๋ง๋ค์ด๋ณผ๊น์?
class UserProfileCard extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
.card { /* ์คํ์ผ์ ์ด์ ๊ณผ ๋์ผ */ }
</style>
<div class="card">
<slot name="avatar"><img src="default-avatar.jpg" alt="Default Avatar"></slot>
<h2 class="name"><slot name="name">์ด๋ฆ ์์</slot></h2>
<p class="skill"><slot name="skill">์คํฌ ์ ๋ณด ์์</slot></p>
<slot name="extra"></slot>
</div>
`;
}
}
customElements.define('user-profile-card', UserProfileCard);
์ด์ ์ด ์ปดํฌ๋ํธ๋ฅผ ์ด๋ ๊ฒ ์ฌ์ฉํ ์ ์์ด์:
<user-profile-card>
<img slot="avatar" src="kim.jpg" alt="๊น์ฌ๋ฅ์ ์๋ฐํ">
<span slot="name">๊น์ฌ๋ฅ</span>
<span slot="skill">์น ๊ฐ๋ฐ</span>
<p slot="extra">์ ๋ ์ด์ ์ ์ธ ๊ฐ๋ฐ์์
๋๋ค!</p>
</user-profile-card>
์ฐ์! ์ด๋ ๊ฒ ํ๋ฉด ์ปดํฌ๋ํธ๋ฅผ ํจ์ฌ ๋ ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์์ด์. ๐
2. CSS ์ปค์คํ ์์ฑ ํ์ฉํ๊ธฐ
CSS ์ปค์คํ ์์ฑ(๋ณ์)์ ์ฌ์ฉํ๋ฉด Shadow DOM ์ธ๋ถ์์ ๋ด๋ถ ์คํ์ผ์ ์ผ๋ถ ์ ์ดํ ์ ์์ด์. ์ฌ๋ฅ๋ท์ ํ ๋ง์ ๋ฐ๋ผ ํ๋กํ ์นด๋์ ์์์ ๋ณ๊ฒฝํ ์ ์๊ฒ ํด๋ณผ๊น์?
class UserProfileCard extends HTMLElement {
// ... ์ด์ ์ฝ๋ ์๋ต ...
connectedCallback() {
this.shadowRoot.innerHTML = `
<style>
.card {
background-color: var(--card-bg, #f0f0f0);
color: var(--card-color, #333);
/* ๋ค๋ฅธ ์คํ์ผ์ ์ด์ ๊ณผ ๋์ผ */
}
</style>
<!-- ์นด๋ ๋ด์ฉ์ ์ด์ ๊ณผ ๋์ผ -->
`;
}
}
customElements.define('user-profile-card', UserProfileCard);
์ด์ ์ธ๋ถ์์ ์ด๋ ๊ฒ ์คํ์ผ์ ๋ณ๊ฒฝํ ์ ์์ด์:
<style>
user-profile-card {
--card-bg: #e1f5fe;
--card-color: #01579b;
}
</style>
์ด๋ ๊ฒ ํ๋ฉด ์ฌ๋ฅ๋ท์ ๋ค์ํ ํ์ด์ง์์ ํ๋กํ ์นด๋์ ์คํ์ผ์ ์ ์ฐํ๊ฒ ์กฐ์ ํ ์ ์์ด์. ๋ฉ์ง์ฃ ? ๐
3. ์ด๋ฒคํธ ์ฌํ๊ฒํ (Retargeting) ์ดํดํ๊ธฐ
Shadow DOM ๋ด๋ถ์์ ๋ฐ์ํ ์ด๋ฒคํธ๋ Shadow ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋์ด๊ฐ ๋ ์ฌํ๊ฒํ ๋ผ์. ์ด๋ฅผ ์ดํดํ๊ณ ํ์ฉํ๋ฉด ์ปดํฌ๋ํธ์ ์ธ๋ถ ์ธ๊ณ์์ ์ํธ์์ฉ์ ๋ ์ ์ ์ดํ ์ ์์ด์.
class UserProfileCard extends HTMLElement {
// ... ์ด์ ์ฝ๋ ์๋ต ...
connectedCallback() {
// ... ์ด์ ์ฝ๋ ์๋ต ...
const nameElement = this.shadowRoot.querySelector('.name');
nameElement.addEventListener('click', (e) => {
const event = new CustomEvent('nameClicked', {
bubbles: true,
composed: true,
detail: { name: nameElement.textContent }
});
this.dispatchEvent(event);
});
}
}
// ์ฌ์ฉ ์:
document.querySelector('user-profile-card').addEventListener('nameClicked', (e) => {
console.log(`${e.detail.name}์ ํ๋กํ์ด ํด๋ฆญ๋์์ต๋๋ค!`);
});
์ด๋ ๊ฒ ํ๋ฉด Shadow DOM ๋ด๋ถ์ ์ด๋ฒคํธ๋ฅผ ์ธ๋ถ๋ก ์ ๋ฌํ ์ ์์ด์. ์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์ ์ด๋ฆ์ ํด๋ฆญํ์ ๋ ํ๋กํ ํ์ด์ง๋ก ์ด๋ํ๋ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๊ฒ ์ฃ ?
๐ ๊ณ ๊ธ ํ: Shadow DOM์ ์ฌ์ฉํ ๋๋ ์ฑ๋ฅ ์ต์ ํ์๋ ์ ๊ฒฝ ์จ์ผ ํด์. ๋๋ฌด ๋ง์ Shadow DOM์ ์ฌ์ฉํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ฆ๊ฐํ ์ ์์ด์. ํ์ํ ๊ฒฝ์ฐ์๋ง ์ ๋ณ์ ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์!
์, ์ฌ๊ธฐ๊น์ง Shadow DOM์ ๊ณ ๊ธ ๊ธฐ์ ๋ค์ ์ดํด๋ดค์ด์. ์ด ๊ธฐ์ ๋ค์ ์ ํ์ฉํ๋ฉด ์ฌ๋ฅ๋ท ๊ฐ์ ๋ณต์กํ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ปดํฌ๋ํธ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ ์ฌ์ฌ์ฉํ ์ ์์ด์. ๐จโ๐ป๐ฉโ๐ป
Shadow DOM์ ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ๋ชจ๋ ์ํฉ์ ์ ํฉํ ๊ฒ์ ์๋์์. ํญ์ ํ๋ก์ ํธ์ ์๊ตฌ์ฌํญ๊ณผ ํน์ฑ์ ๊ณ ๋ คํด์ ์ ์ ํ ์ฌ์ฉํด์ผ ํด์. ๊ทธ๋ฆฌ๊ณ ์ ๊ทผ์ฑ๊ณผ SEO๋ ํญ์ ์ผ๋์ ๋์ด์ผ ํ๋ค๋ ๊ฑธ ์์ง ๋ง์ธ์!
์ฌ๊ธฐ๊น์ง Shadow DOM์ ๋ํด ์ ๋ง ๊น์ด ์๊ฒ ์์๋ดค์ด์. ์ด์ ์ฌ๋ฌ๋ถ์ Shadow DOM์ ์ง์ ํ ๋ง์คํฐ๊ฐ ๋์์ ๊ฑฐ์์! ๐ ์ด ์ง์์ ํ์ฉํด์ ์ฌ๋ฅ๋ท์ ๋์ฑ ๋ฉ์ง ํ๋ซํผ์ผ๋ก ๋ง๋ค์ด๋ณด๋ ๊ฑด ์ด๋จ๊น์? ํ์ดํ ! ๐ช๐
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ