WebComponents - 在组件 Public 界面中使用 CSS 自定义属性有什么好处?

WebComponents - what's the advantage of using CSS Custom Properties in the Component Public Interface?

WebComponent 可能在其封装样式中包含 CSS 自定义属性

这为组件的消费者提供了一种自定义组件样式的方法:

声明中

--fancy-tabs-bg: red

主要样式中表示当shadow-root样式包含

background-color: var(--fancy-tabs-bg, #9E9E9E)

background-color 将是 red(或 --fancy-tabs-bg 设置的任何值)。


但是... 我在同一篇文章中注意到它明确指出:

One gotcha with :host is that rules in the parent page have higher specificity than :host rules defined in the element. That is, outside styles win. This allows users to override your top-level styling from the outside.

再一次,稍后:

Outside styles always win over styles defined in shadow DOM. For example, if the user writes the selector fancy-tabs { width: 500px; }, it will trump the component's rule: :host { width: 650px;}

所以...而不是为 --fancy-tabs-bg 声明一个值,我们可以...为 background-color 设置一个值 (?)

真的吗?让我们一探究竟。

这是一个 WebComponent(主要是从上面引用的文章中复制的),其中组件的前两个实例使用 CSS 自定义 属性(即 --fancy-tabs-bg),第三个实例直接设置样式,使用相关的 CSS 属性(即 background-color).

class FancyTabs extends HTMLElement {
  
  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {
  
    this.root.innerHTML = `
    
    <style>
      :host {
        display: block;
        width: 100px;
        height: 100px;
        margin: 6px;
        border-radius: 10px;
      }
      
      :host([background]) {
        background-color: var(--fancy-tabs-bg, #9E9E9E);
      }
    </style>
    
    `;
  }
}

customElements.define('fancy-tabs', FancyTabs);
fancy-tabs {
  float: left;
}

fancy-tabs:nth-of-type(1) {
  --fancy-tabs-bg: red;
}

fancy-tabs:nth-of-type(2) {
  --fancy-tabs-bg: orange;
}

fancy-tabs:nth-of-type(3) {
  background-color: green;
}
<fancy-tabs background>...</fancy-tabs>
<fancy-tabs background>...</fancy-tabs>
<fancy-tabs background>...</fancy-tabs>

没有区别,是吗?

那么为什么要使用 CSS 自定义属性?为什么要在 public 界面中突出显示特定的 CSS 属性 可用于用户自定义?当然 所有 CSS 属性都可用于用户自定义,不是吗?

我错过了什么?

在处理宿主元素时您不会注意到任何差异,但是当内部有更多元素时您可以清楚地看到 CSS 变量的使用:

示例,其中 CSS 变量可用于更新嵌套元素的样式。我怀疑你能否在没有 CSS 变量的情况下找到更好的方法。

class FancyTabs extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: 'closed' });
    const css = `
     :host {
        display: block;
        width: 100px;
        height: 100px;
        margin: 6px;
        border-radius: 10px;
      }
      
     :host([background]) {
        background-color: var(--fancy-tabs-bg, #9E9E9E);
      }
      div {
        padding: var(--p,0px);
        border:var(--b,0px) solid;
      }`
    this.styles = document.createElement('style');
    this.styles.innerHTML = css;
  }
  connectedCallback() {
    const div = document.createElement('div');
    div.innerHTML = this.innerHTML;
    this.shadow.appendChild(this.styles);
    this.shadow.appendChild(div);
  }
}

customElements.define('fancy-tabs', FancyTabs);
fancy-tabs {
  float: left;
}

fancy-tabs:nth-of-type(1) {
  --fancy-tabs-bg: red;
  --p:20px;
  --b:5px;
}

fancy-tabs:nth-of-type(2) {
  --fancy-tabs-bg: orange;
  --p:10px;
  --b:3px;
}
fancy-tabs:nth-of-type(3) {
  --fancy-tabs-bg: orange;
  padding:20px; /* will get applied to host*/
  border-width:5px; /* will do nothing */
}
<fancy-tabs background>text  here</fancy-tabs>
<fancy-tabs background>text  here</fancy-tabs>
<fancy-tabs background>text  here</fancy-tabs>