[Part 3] Web Components — Shadow DOM과 스타일 격리
Shadow DOM으로 CSS 충돌을 완전히 막는 방법. open/closed 모드 차이, :host, ::slotted, CSS 변수로 외부에서 스타일을 커스터마이즈하는 패턴을 정리합니다.
[Part 3] Web Components — Shadow DOM과 스타일 격리
Part 2에서는 Custom Elements를 사용해서 직접 HTML 태그를 만드는 방법을 알아봤다.
하지만 Custom Elements만 사용하면 한 가지 문제가 남는다.
바로 스타일 충돌이다.
웹 페이지에서는 CSS가 여러 곳에서 작성된다. 프로젝트가 커질수록 공통 CSS, 페이지 CSS, 컴포넌트 CSS, 외부 라이브러리 CSS가 함께 섞인다.
이때 어떤 CSS가 예상하지 못한 곳에 적용되면 화면이 깨질 수 있다.
Shadow DOM은 이런 문제를 줄이기 위해 등장한 기술이다.
1. 스타일 충돌이란?
AD
제휴 광고 · 일부 링크는 수수료를 받을 수 있습니다
스타일 충돌은 내가 의도하지 않은 CSS가 어떤 요소에 적용되는 문제를 말한다.
예를 들어 다음 CSS가 있다고 해보자.
button {
background: red;
color: white;
}
이 CSS는 페이지 안의 모든 <button> 요소에 적용될 수 있다.
<button>저장</button>
<button>삭제</button>
<button>수정</button>
모든 버튼이 빨간색으로 바뀐다.
처음에는 괜찮아 보일 수 있다. 하지만 어떤 컴포넌트 내부 버튼만 검은색이어야 한다면 문제가 된다.
전역 CSS가 컴포넌트 내부까지 영향을 주기 때문이다.
2. 전역 CSS란?
전역 CSS는 페이지 전체에 영향을 줄 수 있는 CSS를 말한다.
button {
background: red;
}
이 코드는 특정 컴포넌트 하나만 대상으로 하지 않는다.
페이지에 있는 모든 button을 대상으로 한다.
전역 CSS는 편리하지만 프로젝트가 커지면 위험해질 수 있다.
- 내가 만든 CSS가 다른 화면에 영향을 줄 수 있다.
- 다른 사람이 만든 CSS가 내 컴포넌트에 영향을 줄 수 있다.
- 클래스 이름이 겹칠 수 있다.
- 어떤 CSS가 실제로 적용되는지 추적하기 어려워질 수 있다.
Shadow DOM은 이런 전역 스타일 충돌을 줄이는 데 도움을 준다.
3. Shadow DOM이란?
Shadow DOM은 컴포넌트 내부에 독립적인 DOM 영역을 만드는 기술이다.
일반 DOM은 페이지 전체와 연결되어 있다.
반면 Shadow DOM은 특정 요소 안에 숨겨진 독립 영역처럼 동작한다.
쉽게 말하면 컴포넌트 내부에 작은 별도 문서를 만드는 것과 비슷하다.
Shadow DOM 안에 작성한 HTML과 CSS는 기본적으로 그 컴포넌트 내부에서만 동작한다.
4. Shadow DOM 만들기
Shadow DOM은 attachShadow() 메서드로 만든다.
class MyButton extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({
mode: 'open'
});
}
}
customElements.define('my-button', MyButton);
코드 리뷰
this는 현재 커스텀 요소인 <my-button>을 의미한다.
attachShadow()는 현재 요소 안에 Shadow DOM을 생성한다.
mode: 'open'은 JavaScript에서 이 Shadow DOM에 접근할 수 있게 한다.
5. Shadow DOM 안에 HTML 넣기
Shadow DOM을 만들었다면 내부에 HTML을 넣을 수 있다.
class MyButton extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({
mode: 'open'
});
shadow.innerHTML = `
<button>확인</button>
`;
}
}
customElements.define('my-button', MyButton);
HTML에서는 다음처럼 사용한다.
<my-button></my-button>
브라우저 개발자 도구에서 보면 대략 다음과 같은 구조로 보인다.
<my-button>
#shadow-root (open)
<button>확인</button>
</my-button>
#shadow-root 안에 있는 button은 일반 DOM이 아니라 Shadow DOM 내부에 있는 요소다.
6. Shadow DOM 안에 CSS 넣기
Shadow DOM의 핵심은 스타일 격리다.
Shadow DOM 내부에 style 태그를 넣어보자.
class MyButton extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({
mode: 'open'
});
shadow.innerHTML = `
<style>
button {
background: black;
color: white;
padding: 10px 16px;
border: none;
}
</style>
<button>확인</button>
`;
}
}
customElements.define('my-button', MyButton);
이 CSS는 Shadow DOM 내부의 button에만 적용된다.
페이지 바깥에 있는 다른 button에는 영향을 주지 않는다.
7. 외부 CSS는 Shadow DOM 내부에 적용될까?
다음과 같은 전역 CSS가 있다고 해보자.
button {
background: red;
}
그리고 <my-button> 내부 Shadow DOM에는 다음 CSS가 있다.
button {
background: black;
}
이 경우 Shadow DOM 내부 button은 검은색으로 표시된다.
외부의 전역 CSS가 Shadow DOM 내부까지 쉽게 들어오지 못하기 때문이다.
이것이 Shadow DOM의 가장 중요한 특징이다.
8. 내부 CSS는 외부에 영향을 줄까?
반대로 Shadow DOM 내부 CSS도 외부 요소에 영향을 주지 않는다.
<style>
button {
background: black;
}
</style>
이 CSS가 Shadow DOM 내부에 있다면 해당 Shadow DOM 내부 button에만 적용된다.
페이지 전체 button을 바꾸지 않는다.
즉 Shadow DOM은 양방향으로 스타일 영향을 줄인다.
- 외부 CSS가 내부로 들어오기 어렵다.
- 내부 CSS가 외부로 나가기 어렵다.
9. mode: open과 mode: closed
Shadow DOM을 만들 때 mode 값을 설정한다.
this.attachShadow({
mode: 'open'
});
mode에는 두 가지가 있다.
openclosed
open은 외부 JavaScript에서 shadowRoot로 접근할 수 있다.
const element = document.querySelector('my-button');
console.log(element.shadowRoot);
closed는 외부에서 shadowRoot로 접근하기 어렵게 만든다.
this.attachShadow({
mode: 'closed'
});
실무에서는 대부분 open을 사용한다.
디버깅이 쉽고, 외부에서 필요한 경우 접근할 수 있기 때문이다.
10. Shadow DOM의 장점
Shadow DOM의 장점은 다음과 같다.
- 스타일 충돌을 줄일 수 있다.
- 컴포넌트 내부 구조를 외부와 분리할 수 있다.
- 컴포넌트 재사용성이 높아진다.
- 디자인 시스템 컴포넌트에 적합하다.
- 외부 페이지에 삽입되는 위젯을 만들 때 유용하다.
여러 프로젝트에서 같은 컴포넌트를 사용할 때 Shadow DOM은 특히 유용하다.
어떤 프로젝트에 들어가도 외부 CSS 때문에 내부 스타일이 쉽게 깨지지 않기 때문이다.
11. Shadow DOM의 단점
Shadow DOM도 단점이 있다.
- 외부 CSS로 내부 스타일을 수정하기 어렵다.
- 기존 CSS 프레임워크와 함께 쓰기 불편할 수 있다.
- 디버깅할 때 구조가 한 단계 더 복잡해진다.
- 테마를 적용하려면 CSS 변수 같은 추가 개념이 필요하다.
즉 Shadow DOM은 무조건 사용해야 하는 기능이 아니라, 목적에 따라 선택해야 하는 기능이다.
12. Shadow DOM을 사용하지 않는 경우
Custom Element는 Shadow DOM 없이도 만들 수 있다.
class MyButton extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<button>확인</button>
`;
}
}
customElements.define('my-button', MyButton);
이 경우 내부 button은 일반 DOM에 들어간다.
그래서 외부 CSS의 영향을 받을 수 있다.
이것은 단점이 될 수도 있지만, 외부 CSS로 쉽게 스타일링할 수 있다는 장점도 된다.
13. 정리
AD
제휴 광고 · 일부 링크는 수수료를 받을 수 있습니다
Shadow DOM은 Web Components에서 스타일과 구조를 격리하기 위한 핵심 기술이다.
- Shadow DOM은 독립적인 DOM 영역을 만든다.
attachShadow()로 생성한다.- Shadow DOM 내부 CSS는 외부에 영향을 주지 않는다.
- 외부 CSS도 Shadow DOM 내부에 쉽게 영향을 주지 못한다.
- 스타일 충돌을 줄이는 데 유용하다.
- mode에는 open과 closed가 있다.
- 실무에서는 대부분 open을 사용한다.
- 무조건 사용해야 하는 것은 아니며 상황에 따라 선택한다.
다음 Part에서는 Template과 Slot을 알아본다.
Template은 재사용할 HTML 구조를 보관하는 기술이고, Slot은 외부 콘텐츠를 컴포넌트 내부에 넣는 기술이다.
AD
제휴 광고
일부 링크는 제휴 링크이며, 구매 또는 가입 시 일정 수수료를 받을 수 있습니다.
AD
'Web components' 카테고리의 다른 글
전체보기- [Part 3] Web Components — Shadow DOM과 스타일 격리 현재 글
- [Part 4] Web Components — Template & Slot으로 유연한 구조 만들기 2026.04.22
- [Part 5] Web Components — Lifecycle Callbacks 완전 이해 2026.04.29
- [Part 6] Web Components — Custom Events와 컴포넌트 통신 2026.05.06
- [Part 7] Web Components — 고급 스타일링 전략 2026.05.13
- [Part 8] Web Components — Form 연동과 ElementInternals 2026.05.20








