这可能是我在 Stack 上的第一个问题!我发现我认为 CSS 属性通过影子 DOM 传递的一个极端情况,尽管提出了著名的修复方案here。
一般背景 我正在构建一个 chrome 扩展,在网站中注入一个弹出窗口。我发现,尽管弹出窗口有 Shadow DOM,但根据它显示的页面,弹出窗口可以有不同的字体。
Shadow DOM 和可继承属性
我了解到可继承的属性往往会通过影子 DOM,这有点道理。例如,如果您有
{font-weight: bold}
,它将传递给影子 DOM 中的所有元素,除非您为影子 DOM 中的元素指定不同的 font-weight
值。
我找到的解决方案是将影子根主机的所有元素设置为其默认值。这样,就不会发生任何泄漏。下面是我们如何保护主 DOM 中的属性
font-weight
和 color
不泄露到影子 DOM 的示例。
<head>
<style>
#mainbod {
font-weight: bold;
color: red;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
let wr = document.getElementById('tata-wrapper');
let shadow = wr.attachShadow({ mode: 'open' });
wr.shadowRoot.innerHTML = `<style> :host { all : initial} !important </style>`
let xp = document.createElement('div')
xp.id = 'explainAI'
xp.innerHTML = `
<style>
.cbd {
background-color: rgb(190, 218, 228);
}
</style>
<div id="popup-container">
<div class="cbd first">
<span>Something else here, maybe this or that.</span>
</div>
</div>
`
wr.shadowRoot.appendChild(xp)
});
</script>
</head>
<body>
<div id="mainbod">
<div>
<p> Some other text</p>
</div>
<div id="tata-wrapper">
</div>
</div>
</body>
边缘案例
到目前为止都很棒!事实证明,这并不稳健。如果主机中的某个属性(在本例中为
tata-wrapper
)碰巧设置为 inherit
,则该值将会泄漏。这是一个示例,我们将 tata-wrapper
的所有属性设置为继承。该 :host { all: initial}
修复不再有效。我们将看到 Shadow DOM 内的元素将是红色且粗体。
<head>
<style>
#mainbod {
font-weight: bold;
color: red;
}
#tata-wrapper {
all: inherit
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function () {
let wr = document.getElementById('tata-wrapper');
let shadow = wr.attachShadow({ mode: 'open' });
wr.shadowRoot.innerHTML = `<style> :host { all : initial} !important </style>`
let xp = document.createElement('div')
xp.id = 'explainAI'
xp.innerHTML = `
<style>
.cbd {
background-color: rgb(190, 218, 228);
}
</style>
<div id="popup-container">
<div class="cbd first">
<span>Something else here, maybe this or that.</span>
</div>
</div>
`
wr.shadowRoot.appendChild(xp)
});
</script>
</head>
<body>
<div id="mainbod">
<div>
<p> Some other text</p>
</div>
<div id="tata-wrapper">
</div>
</div>
</body>
暂定解决方案
我找到的唯一解决方案是实际将实际父级的
all
的值设置为 initial
(即 tata-wrapper
。我按如下方式操作
// start of the code ...
let wr = document.getElementById('tata-wrapper');
wr.style.all = 'initial';
let shadow = wr.attachShadow({ mode: 'open' });
wr.shadowRoot.innerHTML = `<style> :host { all : initial} !important </style>`
let xp = document.createElement('div')
xp.id = 'explainAI'
// rest of the code
我认为这不是一个很好的解决方案,并且可能存在潜在危险。想知道是否有人有解决方案。
这里有一个较短的
all:initial
游乐场可供学习,!important
(在两种设置中)时会发生什么
请注意上面代码中的 your
!important
符号不是正确的语法
<style>
my-component {
background: red;
color: blue !important;
}
</style>
<my-component></my-component>
<script>
customElements.define("my-component", class extends HTMLElement {
constructor() {
super()
.attachShadow({ mode: "open" })
.innerHTML = `
<style>
:host {
display: inline-block;
all: initial !important; /* correct notation for your goal */
color: green;
}
h1 {
background:gold;
}
</style>
<h1>Hello Web Component World!</h1>`;
}
})
</script>