바닐라 자바스크립트(& 타입스크립트)로 개인 사이드 프로젝트를 진행 중인데,
컴포넌트화를 위해 아래 코드와 같이 커스텀 엘리먼트를 생성했다.
⬇️ 커스텀 엘리먼트 <profile-card></profile-card>
import BaseComponent from "../../commons/BaseComponent";
import deviceCheck from "../../utils/deviceCheck";
import './styles.scss'
class ProfileCard extends HTMLElement {
#shadow
constructor() {
super()
this.#shadow = this.attachShadow({mode: 'open'});
this.connectedCallback = this.connectedCallback.bind(this);
}
template (deviceType:number){
console.log('deviceType', deviceType)
if(deviceType == 0){ // mobile
return `
<div class="card-container mobile">
<div class="card-wrapper ">
//front
<div class="profile-card front"></div>
//back
<div class="profile-card back"></div>
</div>
</div>
`
}
if(deviceType == 1){ // pc
return `
<div class="card-container pc">
<div class="card-wrapper ">
// front
// back
</div>
</div>
`
}
}
render(deviceType:number):void{
this.#shadow.innerHTML = this.template(deviceType) as string
}
connectedCallback(){
const deviceType = deviceCheck()
this.render(deviceType)
}
}
export default ProfileCard
⬇️ 스타일링
.card-container {
&.mobile {
width: 25rem;
height: 40rem;
border: 1px solid #000;
}
&.pc {
width: 50rem;
height: 20rem;
border: 1px solid #000;
}
}
내 의도대로 동작을 했다면 직사각형 모형이 화면에 그려져야 하는데,
렌더링된 화면엔 스타일링이 전혀 없었다.

그래서 왜 그런가 생각을 하다가,
Shadow DOM은 보통 CSS 캡슐화를 위해 사용한다는 것이 생각났다.
Claude에게 물어보니, 역시나,
"네, Shadow DOM 때문입니다.
Shadow DOM은 CSS를 캡슐화하기 때문에 외부의 styles.scss가 Shadow DOM 내부에 적용되지 않습니다."
라는 답변과, 해결책 세 가지를 알려줬다.
- Shadow DOM 내부에 직접 스타일 추가하기
template(deviceType: number) { return ` <style> // 여기에 styles.scss 내용을 복사 .card-container { ... } .card-wrapper { ... } // ... </style> <div class="card-container ${deviceType === 0 ? 'mobile' : 'pc'}"> // ... 나머지 템플릿 `; }
이전에 Shadow DOM을 사용해서 커스텀 엘리먼트를 만들었을 땐 스타일링이 단순해서 같이 작성을 했었지만,
이번에는 코드가 길어질 것 같아 왠만하면 분리를 하고 싶었다.
- constructuredStylesheets 사용하기
constructor() {
super();
this.#shadow = this.attachShadow({mode: 'open'});
// styles.scss를 CSSStyleSheet로 변환
const sheet = new CSSStyleSheet();
sheet.replaceSync(`여기에 스타일 내용`);
this.#shadow.adoptedStyleSheets = [sheet];
}
이 방법 외에 다른 방식으로 스타일을 별도 파일로 관리하고 싶다면,
웹팩이나 다른 번들러를 사용해 빌드 시점에 스타일 내용을 문자열로 변환해 템플릿에 주입하는 방법도 있다고 한다.
- Shadow DOM 사용하지 않기
constructor() {
super();
// Shadow DOM 사용하지 않음
this.connectedCallback = this.connectedCallback.bind(this);
}
render(deviceType: number) {
this.innerHTML = this.template(deviceType);
}
Shadow DOM 사용을 유지하면서 스타일 코드를 별도로 관리하고 싶다면 2번을,
굳이 Shadow DOM 을 사용할 필요가 없다면 3번을 택하면 된다.
그렇다면 왜 shadow DOM 을 사용할까?
그리고 shadow DOM은 정확히 뭘까?
가 궁금하다면 해당 링크의 게시물을 참고하면 좋을 것 같다.
'FrontEnd > JavaScript' 카테고리의 다른 글
[ JavaScript ] 특정 값으로 배열 채우기 (0) | 2024.01.16 |
---|---|
[ JavaScript ] 타이핑 효과 (0) | 2024.01.13 |
[ JavaScript ] HTMLCollection 은 forEach가 안된다? (0) | 2023.12.02 |
[ JavaScript ] Object.freeze (0) | 2023.11.27 |
[ JavaScript ] 배열에서 특정 요소 찾기 (0) | 2023.11.13 |