【问题标题】:Importing styles into a web component将样式导入 Web 组件
【发布时间】:2015-04-24 05:04:24
【问题描述】:

将样式导入 Web 组件的规范方法是什么?

以下给我一个错误HTML element <link> is ignored in shadow tree

<template>
    <link rel="style" href="foo.css" />
    <h1>foo</h1>
</template>

我使用 shadow DOM 插入这个:

var importDoc, navBarProto;

importDoc = document.currentScript.ownerDocument;

navBarProto = Object.create(HTMLElement.prototype);
navBarProto.createdCallback = function() {
  var template, templateClone, shadow;

  template = importDoc.querySelector('template');
  templateClone = document.importNode(template.content, true);

  shadow = this.createShadowRoot();
  shadow.appendChild(templateClone);
};

document.registerElement('my-nav-bar', {
  prototype: navBarProto
});

【问题讨论】:

    标签: html web-component shadow-dom


    【解决方案1】:

    现在shadow dom支持直接&lt;link&gt;标签。

    可以直接使用:

    <link rel="stylesheet" href="yourcss1.css">
    <link href="yourcss2.css" rel="stylesheet" type="text/css">  
    

    它已获得 whatwgW3C 的批准。

    在 shadow dom 中使用 css 的有用链接:

    可以在shadow dom中使用直接css链接。

    【讨论】:

    • 当我从外部站点导入样式表时,这对我不起作用。这是禁止的吗? &lt;link rel="stylesheet" href="https://some.site.com/style.css"/&gt;
    【解决方案2】:

    如果您需要在&lt;template&gt; 标签内放置外部样式,您可以尝试

    <style> @import "../my/path/style.css"; </style>
    

    但是我有一种感觉,这将在 元素创建之后开始导入。

    【讨论】:

      【解决方案3】:

      可构造样式表

      这是一个允许构造CSSStyleSheet 对象的新功能。这些可以使用 JavaScript 从 css 文件设置或导入它们的内容,并应用于文档和 Web 组件的影子根。它将在 73 版的 Chrome 中可用,并且可能在不久的将来用于 Firefox。

      有一个good writeup on the Google developers site,但我将在下面简要总结一下,底部有一个示例。

      创建样式表

      您通过调用构造函数创建一个新工作表:

      const sheet = new CSSStyleSheet();
      

      设置和替换样式:

      可以通过调用replacereplaceSync方法来应用样式。

      • replaceSync 是同步的,不能使用任何外部资源:
        sheet.replaceSync(`.redText { color: red }`);
        
      • replaceasynchronous 并且可以接受引用外部资源的 @import 语句。请注意,replace 返回需要相应处理的Promise
        sheet.replace('@import url("myStyle.css")')
          .then(sheet => {
            console.log('Styles loaded successfully');
          })
          .catch(err => {
            console.error('Failed to load:', err);
          });
        

      将样式应用于文档或影子 DOM

      可以通过设置document 或shadow DOM 的adoptedStyleSheets 属性来应用样式。

      document.adoptedStyleSheets = [sheet]
      

      adoptedStyleSheets 中的数组被冻结,不能与push() 发生突变,但可以通过与其现有值组合来连接:

      document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
      

      从文档继承

      shadow DOM 可以以同样的方式从文档的adoptedStyleSheets 继承构造样式:

      // in the custom element class:
      this.shadowRoot.adoptedStyleSheets = [...document.adoptedStyleSheets, myCustomSheet];
      

      请注意,如果它在构造函数中运行,则组件将仅继承在其创建之前采用的样式表。在connectedCallback 中设置adoptedStyleSheets 将为每个实例在连接时继承。值得注意的是,这不会导致FOUC

      Web 组件示例

      让我们创建一个名为 x-card 的组件,它将文本包装在一个样式精美的 div 中。

      // Create the component inside of an IIFE
      (function() {
        // template used for improved performance
        const template = document.createElement('template');
        template.innerHTML = `
          <div id='card'></div>
        `;
      
        // create the stylesheet
        const sheet = new CSSStyleSheet();
        // set its contents by referencing a file
        sheet.replace('@import url("xCardStyle.css")')
        .then(sheet => {
          console.log('Styles loaded successfully');
        })
        .catch(err => {
          console.error('Failed to load:', err);
        });
      
        customElements.define('x-card', class extends HTMLElement {
          constructor() {
            super();
            this.attachShadow({
              mode: 'open'
            });
            // apply the HTML template to the shadow DOM
            this.shadowRoot.appendChild(
              template.content.cloneNode(true)
            );
            // apply the stylesheet to the shadow DOM
            this.shadowRoot.adoptedStyleSheets = [sheet];
          }
      
          connectedCallback() {
            const card = this.shadowRoot.getElementById('card');
            card.textContent = this.textContent;
          }
        });
      
      })();
      <x-card>Example Text</x-card>
      <x-card>More Text</x-card>

      【讨论】:

      • 我在 caniuse.com 上没有看到任何跟踪。 Firefox 对此的支持是什么?到目前为止,这看起来像是 Chrome 独有的技术,对吧?
      【解决方案4】:

      注意!!!

      此答案已过时

      请检查下面 Himanshu Sharma 的答案

      最新答案:https://stackoverflow.com/a/48202206/2035262

      根据Polymer documentation:

      Polymer 允许您在 &lt;polymer-element&gt; 定义中包含样式表,该功能Shadow DOM 本身不支持

      这是一个有点奇怪的参考,但我无法直接用谷歌搜索。目前似乎没有关于模板内支持链接的传言。

      也就是说,无论你想使用 vanilla web 组件,你都应该使用 &lt;style&gt; 标签内联你的 css,或者在 javascript 中手动加载并应用你的 css

      【讨论】:

      • 如果您使用的是 1.0,那么这已经过时了:https://www.polymer-project.org/1.0/docs/devguide/styling.html
      • @7immy 是的,这是因为严重的生产力损失。
      • 这是较旧的答案且已过时。请参阅下面的答案。
      • @Himanshusharma 谢谢,我已经更新了链接到您最新版本的答案。
      【解决方案5】:

      上面的答案展示了如何将样式表导入到 Web 组件中,但是可以通过编程方式将单个样式导入到影子 DOM 中。这是我最近开发的技术。

      首先 - 确保将组件本地样式直接嵌入到带有 HTML 代码的模板中。这是为了确保 shadow DOM 在你的元素构造函数中有一个样式表。 (导入其他样式表应该没问题,但你必须在构造函数中准备好一个)

      第二个 - 使用 css 变量指向要导入的 css 规则。

      #rule-to-import {
         background-color: #ffff00;
      }
      
      my-element {
         --my-import: #rule-to-import;
      }
      

      第三 - 在组件构造器中,读取 CSS 变量并在文档样式表中找到指向的样式。找到后,复制字符串但重写选择器以匹配您希望设置样式的内部元素。我为此使用了一个辅助函数。

      importVarStyle(shadow,cssvar,target) {
          // Get the value of the specified CSS variable
          const varstyle=getComputedStyle(this).getPropertyValue(cssvar).trim();
          if(varstyle!="") varstyle: {
              const ownstyle=shadow.styleSheets[0];
              for(let ssheet of document.styleSheets) {   // Walk through all CSS rules looking for a matching rule
                  for(let cssrule of ssheet.cssRules) {
                      if(cssrule.selectorText==varstyle) {    // If a match is found, re-target and clone the rule into the component-local stylesheet
                          ownstyle.insertRule(
                              cssrule.cssText.replace(/^[^{]*/,target),
                              ownstyle.cssRules.length
                          );
                          break varstyle;
                      }
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        尝试&lt;template&gt; 内部的&lt;style&gt; 元素:

        <template>
            <style>
               h1 { 
                 color: red;
                 font-family: sans-serif;
               }
            </style>
            <h1>foo</h1>
        </template>
        

        【讨论】:

        • 问题是关于导入样式,而不是嵌入。
        • 是的,但我认为您根本无法在
        猜你喜欢
        • 2021-09-29
        • 1970-01-01
        • 2018-08-05
        • 2020-02-23
        • 2020-11-24
        • 1970-01-01
        • 2020-08-20
        • 2021-10-09
        • 2022-01-26
        相关资源
        最近更新 更多