Safari adoptedStyleSheets 삭제 후 스타일이 남는 이유
Safari에서 컴포넌트 하나의 옛 테마가 남아 CSS 내용을 비웠더니 다른 컴포넌트의 색상까지 사라졌다. 한 곳에서만 스타일시트를 떼려면 무엇을 바꿔야 할까?

- 한 컴포넌트에서 시트를 해제할 때는 해당 루트의 adoptedStyleSheets를 바꾼다.
- 공유 CSSStyleSheet의 내용을 비우면 그 시트를 쓰는 다른 곳에도 영향을 준다.
- STP 255에는 길이 축소 뒤 스타일 잔류와 중복 제거 뒤 갱신 누락 수정이 포함됐다.
시트 내용을 지우는 것과 연결을 끊는 것은 다르다
웹 컴포넌트를 해제하거나 테마를 교체했는데 이전 색상이 남는다면, 먼저 무엇을 삭제했는지 봐야 한다. adoptedStyleSheets에는 자바스크립트로 만든 스타일시트 중 문서에 적용할 객체들을 넣는다. 섀도 DOM은 각각 자기 루트의 배열을 가진다.
하나의 CSSStyleSheet 객체는 여러 루트가 공유할 수 있다. 따라서 sheet.replaceSync('')로 내용을 비우면 그 객체를 채택한 다른 컴포넌트도 영향을 받는다. 한 곳에서만 테마를 해제하려면 해당 루트의 배열에서 그 객체 참조를 빼는 방식이 목적에 맞는다.
// root: document 또는 대상 ShadowRoot
// themeSheet: 해제할 때까지 보관한 CSSStyleSheet 객체
root.adoptedStyleSheets = root.adoptedStyleSheets.filter(
(candidate) => candidate !== themeSheet
); 이 예는 같은 객체가 여러 번 들어 있으면 해당 참조를 모두 제거하고 다른 시트의 순서는 유지한다. 같은 CSS 문자열로 새 시트를 만들어 비교하면 원래 객체를 찾을 수 없다. 등록한 객체를 해제 시점까지 보관하고, 제거 뒤에는 배열과 화면의 변화가 일치하는지 확인해야 한다.
Safari 프리뷰는 제거와 갱신의 두 문제를 고쳤다
Safari Technology Preview 255는 배열 길이를 줄였는데 제거된 시트가 계속 적용되는 오류를 수정했다. 같은 시트의 중복 참조 하나를 제거한 뒤 그 시트의 변경을 무시하던 문제도 함께 수정했다.
두 증상은 관찰 지점이 다르다. 첫 번째는 제거 후 화면이 원래 스타일로 돌아오는지, 두 번째는 남아 있는 시트를 수정했을 때 화면이 갱신되는지를 본다. macOS용 시험판의 수정이므로 정식 Safari와 iOS에서 같은 결과가 나오는지는 사용하는 버전으로 확인해야 한다.
배열·루트·스타일 변화를 같은 순서로 기록한다
진단은 시트를 등록한 대상에서 시작한다. 문서 배열에서 지웠어도 섀도 루트가 계속 채택하고 있다면 그 안의 스타일이 남는 것은 예상 가능한 결과다. 반대로 시트 객체 자체를 변경하면 여러 루트에 한꺼번에 반영된다. 구성 가능한 스타일시트의 공유 방식을 염두에 둬야 한다.
- 등록 대상이 document인지 특정 ShadowRoot인지 확인한다.
- 제거 전후 배열 길이와 대상 객체의 포함 여부를 기록한다.
- 중복 참조가 있었다면 하나를 남긴 경우와 모두 뺀 경우를 나눠 본다.
- 남긴 시트를 변경한 뒤 대상 요소의 계산된 색상 등 실제 스타일 값을 비교한다.
시트의 내용 교체에는 replaceSync()가 쓰인다. 이 메서드는 규칙을 동기적으로 교체한다. 연결 해제 코드와 내용 변경 코드를 섞지 않고 비교해야 어느 단계에서 결과가 달라지는지 알 수 있다.
오래된 length 오류나 Inspector 잠김과 혼동하지 않는다
검색되는 WebKit 260716번 제보는 2023년 length를 쓸 수 없던 문제다. 당시 수정 완료로 닫힌 별도 기록이므로, 지금의 스타일 잔류 현상을 같은 오류라고 단정할 수 없다.
Web Inspector에서 시트가 읽기 전용으로 보인다는 제보도 화면의 스타일 적용 여부와는 구분해야 한다. 먼저 배열에서 참조가 실제로 빠졌는지, 남은 공유 시트의 수정이 전파되는지 확인한다. 그 결과를 기준으로 Safari 버전을 비교하면 다른 컴포넌트의 테마까지 지우지 않고 문제 범위를 좁힐 수 있다.