:host:defined 不起作用, :host(:defined) 起作用

:host:defined doesn't work, :host(:defined) works

是否不能或不允许合并 :host and :defined in CSS, while combining the latter with the :host() 伪类作品?

正如您在下面的示例中看到的,以下

:host:defined { display: block; }

有效,而

:host(:defined) { display: block; }

有效。

class CustomElement extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: 'closed' });
    const css = `
      :host { display: none; }
      :host:defined { display: block; }  
      `;
    this.styles = document.createElement('style');
    this.styles.innerHTML = css;
  }
  connectedCallback() {
    const div = document.createElement('div');
    div.innerHTML = `<code>&lt;${this.tagName.toLowerCase()}&gt;</code> connected!`;
    this.shadow.appendChild(this.styles);
    this.shadow.appendChild(div);
  }
}
class OtherCustomElement extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: 'closed' });
    const css = `
      :host { display: none; }
      :host(:defined) { display: block; }  
      `;
    this.styles = document.createElement('style');
    this.styles.innerHTML = css;
  }
  connectedCallback() {
    const div = document.createElement('div');
    div.innerHTML = `<code>&lt;${this.tagName.toLowerCase()}&gt;</code> connected!`;
    this.shadow.appendChild(this.styles);
    this.shadow.appendChild(div);
  }
}

customElements.define('custom-element', CustomElement);
customElements.define('other-custom-element', OtherCustomElement);
<custom-element></custom-element>
<other-custom-element></other-custom-element>

codepen 上面的代码示例:https://codepen.io/connexo/pen/GRKEGax

the specification我们可以读到:

The :host pseudo-class, when evaluated in the context of a shadow tree, matches the shadow tree’s shadow host. In any other context, it matches nothing

The :host() function pseudo-class has the syntax: :host( <compound-selector-list> ) When evaluated in the context of a shadow tree, it matches the shadow tree’s shadow host if the shadow host, in its normal context, matches the selector argument. In any other context, it matches nothing.

基本上,:host 将匹配影子主机,仅此而已。您不能将它与任何其他 selector 结合使用,而第二种语法允许您在 ().

中添加 selector

如果您参考规范中显示的示例:

say you had a component with a shadow tree like the following:

<x-foo class="foo">
  <"shadow tree">
    <div class="foo">...</div>
  </>
</x-foo>

For a stylesheet within the shadow tree:

  1. :host matches the <x-foo> element.

  2. x-foo matches nothing.

  3. .foo matches only the element.

  4. .foo:host matches nothing

  5. :host(.foo) matches the element.

注意 (2) 和 (4)。 (2) selecting 什么都没有,因为没有共同的 selector can select 外影子树。只有 :host:host() 可以做到。 (4) select 什么都没有,因为 :host 被设计为单独用于 select shadow host 但是如果你想添加另一个select或者您必须像 (5) 中那样使用 :host()

这里有一个基本的例子来说明:

class CustomElement extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: 'closed' });
    const css = `
      :host.box { color:red; }  
      `;
    this.styles = document.createElement('style');
    this.styles.innerHTML = css;
  }
  connectedCallback() {
    const div = document.createElement('div');
    div.innerHTML = `<code>&lt;${this.tagName.toLowerCase()}&gt;</code> connected!`;
    this.shadow.appendChild(this.styles);
    this.shadow.appendChild(div);
  }
}
class OtherCustomElement extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: 'closed' });
    const css = `
      :host(.box) { color:red }  
      `;
    this.styles = document.createElement('style');
    this.styles.innerHTML = css;
  }
  connectedCallback() {
    const div = document.createElement('div');
    div.innerHTML = `<code>&lt;${this.tagName.toLowerCase()}&gt;</code> connected!`;
    this.shadow.appendChild(this.styles);
    this.shadow.appendChild(div);
  }
}

customElements.define('custom-element', CustomElement);
customElements.define('other-custom-element', OtherCustomElement);
<custom-element class="box"></custom-element>
<other-custom-element class="box"></other-custom-element>

现在的问题是:当我们可以简单地将 :host 与任何其他 selector 组合时,为什么我们有两种 selector。

这是为了在解析 selector 时避免混淆和歧义,因为影子主机只能由特殊的 selector 编辑 select。如果我们写 :host.foo 浏览器将尝试将元素与 .foo:host 匹配,但这会很棘手,因为 .foo 只能匹配影子树中的元素,而 :host 可以到外面去解析 selector 来判断是否有 :host 在里面,以便考虑 select 的剩余部分或者匹配影子主机会很乏味。

使用 :host() 让浏览器更容易解析 selector 和 :host:host() 没有 selector 的特例.

Note: This is different from the specificity of similar pseudo-classes, like :matches() or :not(), which only take the specificity of their argument. This is because :host is affirmatively selecting an element all by itself, like a "normal" pseudo-class; it takes a selector argument for syntactic reasons (we can’t say that :host.foo matches but .foo doesn’t), but is otherwise identical to just using :host followed by a selector.

请注意 我们不能说 :host.foo 匹配但 .foo 不匹配