css 为什么Font Awesome在我的Shadow DOM中不起作用?

uajslkp6  于 2023-05-30  发布在  其他
关注(0)|答案(6)|浏览(165)

Font Awesome在我的shadow DOM中不起作用,因为我在其中有以下内容来防止样式泄漏:

:host {
    all: initial; /* 1st rule so subsequent properties are reset. */
    display: block;
    contain: content; /* Boom. CSS containment FTW. */
}

我可以通过将其他样式表内联到:host属性中来使用它们,但这对Font Awesome不起作用,因为它在样式表中使用相对路径。
我找到了this post,并尝试使用我实现的scoped CSS,但图标显示为正方形,如在my example中所见。

jc3wubiy

jc3wubiy1#

Stenciljs的新方法--- 2023年更新
如果您使用Stenciljs,并希望将字体直接与您的捆绑包一起发布并在任何地方使用它,那么以下两个选项之一适合您:

**第一种:**使用全局样式表。https://stenciljs.com/docs/styling#global-styles。在全局样式表中,您可以像往常一样导入字体:

@font-face {
font-family: 'special-font';
src: url('/assets/fonts/special-font.ttf') format('truetype');
}

h1,h2,h3,h4,h5 {
  font-family: 'special-font' !important;
}

这会将字体应用于页面上的所有标题(Web组件以及普通页面上的所有元素)。一切都是通过你的模板包送达。注意不要不小心覆盖你的正常网站的样式。

第二种选择:新建一个类似<ci-styling></ci-styling>的组件,将你所有的样式插入到这个组件中。然后你只需要在@Component装饰器中设置shadow: false。这样,组件就不再使用shadow dom了,并且样式在任何地方都可用,就像第一个选项一样。使用这种方法,您可以始终单独决定每页,如果您想要例如。字体或不通过简单地加载或不加载这个组件。

@Component({
  tag: 'ci-styles',
  styleUrls: ['ci-styles.scss'],
  shadow: false,
})

2019年的原始答案(仍然有效)

**第三个选择:**经过几个小时的斗争和@Intervalia的回答,我能够解决它。

问题是,当字体文件只包含在shadow dom(您的自定义web组件)中时,浏览器不会加载它们。这意味着字体也必须包含在普通的html文件(又名light DOM)中,以便浏览器可以检测和加载它们,以便在shadow dom中使用它们。
在我的例子中,我没有使用Font awesome,而是使用了一种自定义字体,但我用font awesome和一个干净的Stenciljs项目再次尝试了它。解决方案总是相同的,不管你需要哪种自定义字体。

**第一步:**将字体移动到项目中。我在“src”文件夹中创建了一个单独的“assets”文件夹,以便可以访问所有组件。在这个例子中,我下载了web环境下的font awesome https://fontawesome.com/download。(我不推荐使用npm install,因为你也必须在index.html中使用它)

第二步:准备web组件(本例中为my-component.tsx)。可以使用styleUrls属性导入多个css文件。只需从assets目录导入fontawesome css即可。

import { Component, Prop, h } from '@stencil/core';

@Component({
  tag: 'my-component',
  styleUrls: [
    'my-component.css',
    '../../assets/fontawesome/css/all.css'
],
  shadow: true
})
export class MyComponent {
  @Prop() first: string;

  render() {
    return <div> <i class="fas fa-question-circle"></i> </div>;
  }
}

第3步准备要使用组件的文件(本例中为index.html)。重要的一行是“link”标签。这包括“字体真棒CSS”再次和强制浏览器真正下载的字体。

<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
  <meta charset="utf-8">
  <title>Stencil Component Starter</title>
  <link rel="stylesheet" type="text/css" href="./assets/fontawesome/css/all.css">
</head>
<body>

  <my-component first="Stencil" last="'Don't call me a framework' JS"></my-component>

</body>
</html>

我知道这感觉不对,看起来很奇怪,但仅仅在索引html或web组件中包含font awesome是不够的。它必须包含在两个文件中。这并不意味着浏览器将加载它多次-它只会加载一次。
这意味着你不能提供字体与网络组件-据我所知。这不是stenciljs的bug,这是浏览器的一个普遍问题。请让我知道如果你有更好的解决方案。
只是为了好玩,这里是一个屏幕截图,显示浏览器不加载字体时,它只包括在一个文件。http://prntscr.com/p2f9tc
更新05.10.2019:
如果你想在你的web组件中使用你的字体,上面的解释是正确的,仍然是必要的。但是你也可以在web组件中使用slot标签。然后你会自动绕过字体从外部(html)进入web组件。但请注意,它只适用于您在Web组件的标记之间编写的内容。这意味着您可以使用<my-component> <i class="your-font"/> </my-component>。在这种情况下,您不必将字体导入Web组件。

3gtaxfhh

3gtaxfhh2#

我注意到的一件事是,如果页面没有加载CSS文件,那么shadowDOM也不会加载它。
我真的认为唯一的问题是,如果字体没有在页面上定义,它将无法在组件中工作,因为CSS的其余部分似乎可以正确地应用于shadowDOM元素。
这个例子显示了shadowDOM试图加载CSS,但它不起作用:

let template = `
<style>
:host {
  display: block;
}
</style>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<header>
  <h1>DreamLine</h1>
  <nav>
    <ul>
      <li><a href="#0">Tour</a></li>
      <li><a href="#0">Blog</a></li>
      <li><a href="#0">Contact</a></li>
      <li><a href="#0">Error</a></li>
      <li><a href="#0"><i class="fa fa-search"></i> Search</a></li>
    </ul>
  </nav>
</header>
`;

class MyEl extends HTMLElement {
  connectedCallback() {
    this.attachShadow({mode: 'open'}).innerHTML = template;
  }
}

customElements.define("blog-header", MyEl);
<i class="fa fa-battery-full" style="font-size: 45px;"></i>
<hr/>
<blog-header></blog-header>
<hr/>

这个例子展示了页面和shadowDOM加载它,它工作了:

let template = `
<style>
:host {
  display: block;
}
</style>
<header>
  <h1>DreamLine</h1>
  <nav>
    <ul>
      <li><a href="#0">Tour</a></li>
      <li><a href="#0">Blog</a></li>
      <li><a href="#0">Contact</a></li>
      <li><a href="#0">Error</a></li>
      <li><a href="#0"><i class="fa fa-search"></i> Search</a></li>
    </ul>
  </nav>
</header>
`;

class MyEl extends HTMLElement {
  connectedCallback() {
    const styles = document.querySelector('link[href*="fontawesome"]');
    this.attachShadow({mode: 'open'}).innerHTML = template;
    if (styles) {
      this.shadowRoot.appendChild(styles.cloneNode());
    }
  }
}

customElements.define("blog-header", MyEl);
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">

<i class="fa fa-battery-full" style="font-size: 45px;"></i>
<hr/>
<blog-header></blog-header>
<hr/>

我喜欢使用的代码在body中查找所需的<link>标记,然后在shadowDOM中使用该标记的克隆。这样我的组件就不会不同步了。是的,这可能会导致问题如果组件不期望CSS中的更改,但我发现它对我的项目很有效。

z0qdvdin

z0qdvdin3#

如果你不需要阴影:true则可以通过index.html或主应用程序直接加载all.min.css。即使加载all.min.js文件也可以工作。
如果你需要在shadow dom中使用它,那么你需要在index.html中加载all.min.css,并在shadow root中使用类似这样的方法加载它。

componentDidLoad(): void {
  this.hostElement.shadowRoot
    .getElementById("some_Id")
    .insertAdjacentHTML(
      "afterbegin",
      `<link rel="stylesheet" href="${getAssetPath(
        "/fontAssets/fontawesome-free/css/all.min.css"
      )}" />`
    );
}

vs3odd8k

vs3odd8k4#

我想分享我所做的加载字体真棒图标到我的模具组件(阴影启用)...
经过几个小时的研究这个主题,我想我已经发现了一个解决方案,这将是最有效的我的组件捆绑在一个不可知的方式和任何额外的样式表包括在HTML头。
我的解决方案是使用stencil-inline-svg模块,然后直接从Font Awesome模块导入svg文件,如下所示:

// the reference to the svg can be anything (searchIcon name).
// just make sure to import the correct svg from fontawesome node modules.
import searchIcon from 'fontawesome/svgs/regular/search.svg';

@Component({
  tag: 'search-icon',
  styleUrl: 'search-icon.scss',
  shadow: true,
})

export class SearchIconComponent {
  render(){
    return (
      {/* Not ideal to use innerHTML but this renders the full SVG markup */}
      <span class="search-btn" innerHTML={searchIcon}></span>
    )
  }
}

现在,我可以像这样设置css规则来修改我的图标的颜色和大小

.search-btn {
        width: 40px; // Set SVG size at the parent.

        svg path {
            fill: #fff; // Update svg path color.
        }
    }

显然,这需要一点Font Awesome图标知识,以便您知道要导入哪些图标。

hgqdbh6s

hgqdbh6s5#

Shadow Doms的风格是有范围的。而且它不会影响外部风格

xa9qqrwz

xa9qqrwz6#

我创建了一个helper方法来在父页面级别为font-awesome创建一个链接。不确定这是否违反了任何custom-elements/Web Components标准,但我会继续并在这里发布,希望我能得到纠正:)虽然现在它适用于我的用例w/内部Web应用程序。

export const addFontAwesomeStyles = () => {
    injectStylesheet("https://use.fontawesome.com/releases/v5.13.0/css/all.css");
    injectStylesheet("https://use.fontawesome.com/releases/v5.13.0/css/v4-shims.css");
}

export const injectStylesheet = (href: string) => {
    const links = document.head.querySelectorAll("link");

    // Already been injected
    for(let l in links)
        if(links[l].href == href) return;

    const link = document.createElement('link');
    link.rel = "stylesheet";
    link.href = href;
    document.head.appendChild(link)
}

然后在StencilJS组件的构造器中,你可以这样使用它:

//...
constructor() {
    addFontAwesomeStyles();
}

相关问题