将开槽样式优先于全局样式

Prioritizing slotted styling over global styling

假设我有一个应用程序,默认情况下段落为红色,但我想使用自定义元素(我们称之为 <blue-stuff>)将某些段落设置为蓝色和粗体。在下面的代码片段中,我尝试使用 Web 组件和阴影 dom 执行此操作,依赖于 ::slotted 伪元素:

customElements.define('blue-stuff', class extends HTMLElement {
  constructor() {
    super()
      .attachShadow({ mode: 'open' })
      .appendChild(document.importNode(document.getElementById('blue-template').content, true))
  }
})
p {
  color: red;
}
<template id="blue-template">
  <style>
    .blue ::slotted(p) {
      color: blue;
      font-weight: bold;
    }
  </style>
  
  <div class="blue">
    <slot></slot>
  </div>
</template>

<p>Hello I am red!</p>
<blue-stuff>
  <p>Hello, I am supposed to be blue and bold!</p>
</blue-stuff>

令我惊讶的是,本应为蓝色的段落实际上是红色的,这意味着它优先考虑简单的 p selector 而不是 .blue ::slotted(p) selector .通常,特异性会解决这个问题,但在这种情况下,“光”样式 dom 比阴影 dom.

更受欢迎

问题:在我的示例中,是否可以将 <blue-stuff> 中的段落样式设置为蓝色而不使用 !important

目前想到的:

我在 Firefox 中处理过这个问题。

你落入了<slot>陷阱

长答案见:

  • 一个。开槽元素反映在阴影DOM中,它未移动到阴影DOM<slot>

  • 乙。开槽内容的样式来自容器(隐藏)lightDOM 元素定义在
    在你的情况下,这是主要的 DOM

customElements.define('blue-stuff', class extends HTMLElement {
  constructor() {
    super()
      .attachShadow({
        mode: 'open'
      })
      .append(document.getElementById(this.nodeName).content.cloneNode(true));
    this.onclick = () => BLUE.disabled = !BLUE.disabled;
  }
})
p {
  color: red;
  font-size: 20px;
  font-family: Arial;
}
span {
  background:gold;
}
<template id="BLUE-STUFF">
  <style>
   ::slotted(p) {
      color      : blue;  /* not applied because inheritable color:red */
      font-weight: bold;  /* applied, no inherited setting */
      cursor: pointer;    /* applied, no inherited setting */
      font-family: Georgia !important; /* be a crap Designer, force it */
    }
    ::slotted(span){
        background:black !important; 
        /* won't work, ::slotted can only style lightDOM 'skin' (p) */
    }
  </style>
  <slot></slot>
</template>
<style id=BLUE onload="this.disabled=true">/* click to toggle stylesheet */
  blue-stuff p{
    color:blue;  
    font-weight: normal;
    font-family: Arial !important; /* not applied, fire that 'designer'! */
  }
</style>
<blue-stuff>
  <p>I <span>should</span> be styled by my container DOM [click me]</p>
</blue-stuff>

  • 因为 A. 和 B. ::slotted() 对特异性有任何影响

  • 与字体相关的 CSS 是 inheritable styles,滴入阴影DOM,
    这就是 font-size 变成 20px
    的原因 大多数 CSS 不会 滴入阴影 DOM,但 CSS-properties 会[=22] =]

  • 应用了字体粗细,因为还没有定义字体粗细

  • 强制你的蓝色的唯一方法是在 ::slotted 选择器中使用 !important
    font-family

  • 但是你的风格应该来自主 DOM:

blue-stuff p{
  color:blue
}