Shared styling with custom HTML elements?

℡╲_俬逩灬. 提交于 2021-01-27 11:42:56

问题


I'm beginning to use custom elements, and one thing I can't figure out is sharing styling. For example, if I have 2 custom elements, <element-1> and <element-2>, both of which contain <button>'s, and i want all buttons to have a certain styling, e.g. font-size:20px.

The options I've considered are:

  1. Use a <stylized-button> custom element instead of <button> in the custom elements. This is problematic when externally sourcing <element-1>. Also problematic if you want other styling as well (e.g. color:red) on only <element-1> buttons and not <element-2> buttons.

  2. As far as I could tell from polymer's docs [1], polymer doesn't have a solution for this either.

  3. /dead/ and :shadow seemed promising but are no longer supported.

  4. Similarly @apply [2] seemed promising, but the proposal was withdrawn.

  5. ::part and ::theme [3] seem even more promising, but aren't yet supported.

  6. Use js to support ::part and ::theme [4]. i imagine this would be very brittle without ironing out all cases.

  7. Explicitly add the shared styling to each custom element.

    class Element1 extends HTMLElement {
        constructor() {
            this.shadowRoot.addElement(sharedStyle);
        }
    }
    

    This seems very restricted & manual. Also might affect performance? Also problematic if you externally sourcing <element-1>.

Right now, I'm thinking #5 might be the best as it seems the most generic / easiest to use without building specifically for it, plus it would make transitioning to #4 trivial when it's implemented. But I'm wondering if there are other approaches or suggestions?

[1] https://www.polymer-project.org/3.0/docs/devguide/style-shadow-dom

[2] http://tabatkins.github.io/specs/css-apply-rule/

[3] https://meowni.ca/posts/part-theme-explainer/

[4] A naive implementation and an example using it: https://gist.github.com/mahhov/cbb27fcdde4ad45715d2df3b3ce7be40

implementation:

document.addEventListener('DOMContentLoaded', () => {
    // create style sheets for each shadow root to which we will later add rules
    let shadowRootsStyleSheets = [...document.querySelectorAll('*')]
        .filter(element => element.shadowRoot)
        .map(element => element.shadowRoot)
        .map(shadowRoot => {
          shadowRoot.appendChild(document.createElement('style'));
          return shadowRoot.styleSheets[0];
        });

    // iterate all style rules in the document searching for `.theme` and `.part` in the selectors.
    [...document.styleSheets]
        .flatMap(styleSheet => [...styleSheet.rules])
        .forEach(rule => {
          let styleText = rule.cssText.match(/\{(.*)\}/)[1];

          let match;
          if (match = rule.selectorText.match(/\.theme\b(.*)/))
            shadowRootsStyleSheets.forEach(styleSheet => styleSheet.addRule(match[1], styleText));
          else if (match = rule.selectorText.match(/\.part\b(.*)/))
            shadowRootsStyleSheets.forEach(styleSheet => styleSheet.addRule(`[part=${match[1]}]`, styleText));
        });
  });

and the usage:

<style>
  .my-element.part line-green {
    border: 1px solid green;
    color: green;
  }

  .theme .line-orange {
    border: 1px solid orange;
    color: orange;
  }

  /*
    must use `.part` instead of `::part`, and `.theme` instead of `::theme`
    as the browser prunes out invalid css rules form the `StyleSheetList`'s. 
  */
</style>

<template id="my-template">
  <p part="line-green">green</p>
  <p class="line-orange">orange</p>
</template>

<my-element></my-element>

<script>
  customElements.define('my-element', class extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({mode: 'open'});
      const template = document.getElementById('my-template').content.cloneNode(true);
      this.shadowRoot.appendChild(template);
    }
  });
</script>

回答1:


You can use @import url to import an external stylesheet into different custom elements.

Alternately now you can also use <link rel="stylesheet"> inside a custom element Shadow DOM:

<template id="element-1">
  <style> 
      @import url( 'button-style.css' )
  </style>
  <button>B-1</button>
</template>

<template id="element-2">
  <link rel="stylesheet" href="button-style.css">
  <button>B-2</button>
</template>



回答2:


If you are using css, you can just do this:

button {

  /* Put Style Here */  

}

You also have to add a link in the head on html:

<link rel=“stylesheet” href=“the address”>


来源:https://stackoverflow.com/questions/53089691/shared-styling-with-custom-html-elements

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!