Shadow DOM이란?
웹 페이지를 개발하다 보면 CSS 클래스 이름이 겹쳐서 스타일이 깨지는 경험을 한 번쯤 해봤을 것이다. 특히 여러 명이 함께 작업하거나 외부 라이브러리를 가져다 쓸 때, 내가 만든 ‘.button’ 스타일이 다른 곳의 ‘.button’과 충돌해버리는 문제가 자주 발생한다. Shadow DOM은 이런 문제를 해결하기 위해 브라우저가 제공하는 기능으로, 특정 DOM 요소 내부에 그림자처럼 독립된 DOM 트리를 만들어 그 안의 스타일과 마크업이 외부에 영향을 주거나 받지 않도록 격리하는 기술이다.
쉽게 비유하면, 아파트의 각 세대는 같은 건물 안에 있지만 내부 인테리어는 서로 영향을 주지 않는 것과 비슷하다. 옆집에서 벽지를 바꿔도 우리 집 벽지는 그대로인 것처럼, Shadow DOM 안의 스타일은 바깥 문서의 CSS에 전혀 영향을 받지 않는다.
동작 원리와 예시
Shadow DOM은 자바스크립트로 특정 요소에 그림자 루트(shadow root)를 붙이는 방식으로 동작한다. 이 그림자 루트 안에 있는 요소들은 별도의 DOM 트리를 이루며, 여기에 작성한 style 태그는 오직 그림자 루트 내부에만 적용된다.
예를 들어 아래와 같이 커스텀 엘리먼트를 만들 수 있다.
const host = document.querySelector('#my-widget'); const shadow = host.attachShadow({ mode: 'open' }); shadow.innerHTML = '
이 문단은 빨간색입니다
';
여기서 ‘mode: open’으로 설정하면 외부 자바스크립트에서도 ‘host.shadowRoot’를 통해 내부 구조에 접근할 수 있고, ‘closed’로 설정하면 완전히 캡슐화되어 접근이 차단된다. 중요한 점은 이 안에 정의한 ‘p’ 태그 스타일이 문서 전체의 ‘p’ 태그에는 절대 영향을 주지 않는다는 것이다.
실무에서 왜 쓰는지
Shadow DOM은 웹 컴포넌트(Web Components) 표준의 핵심 요소 중 하나로, 재사용 가능한 UI 컴포넌트를 만들 때 특히 유용하다. 실무에서 이를 활용하는 이유는 다음과 같다.
- 스타일 충돌 방지: 여러 팀이 함께 작업해도 CSS 클래스 이름이 겹칠 걱정이 없다.
- 컴포넌트 캡슐화: 내부 마크업 구조를 숨기고 필요한 인터페이스만 노출할 수 있다.
- 서드파티 위젯 배포: 다른 사이트에 삽입해도 해당 사이트의 CSS에 영향을 받지 않는 안정적인 위젯을 만들 수 있다.
실제로 유튜브의 ‘youtube-video’ 태그나 크롬 브라우저의 ‘video’ 재생 컨트롤 UI도 내부적으로 Shadow DOM을 사용해 만들어져 있다. React나 Vue 같은 프레임워크는 기본적으로 Shadow DOM을 사용하지 않지만, 순수 웹 컴포넌트를 만들거나 디자인 시스템을 라이브러리 형태로 배포할 때는 Shadow DOM을 이해하고 있으면 훨씬 견고한 컴포넌트를 설계할 수 있다.