Web组件-字体和材料图标不起作用(@font-face)

6
我正在尝试使用vue cli 3创建Web组件,通过运行以下命令:vue-cli-service build --target wc --name wc-demo 'src/App.vue'。我在Web组件中加载字体和Material图标时遇到了问题。我在App.vue的样式标签中导入了roboto-font.scssmaterial-icon.scss,这是创建Web组件的入口。
<style lang='scss'>
// @import url('https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap');
@import "~@/assets/fonts/roboto-font/roboto-font.scss";
@import "~@/assets/fonts/material-icons/material-icons.scss";
</style>

Material-icon.scss

$font-dir: "assets/fonts/material-icons/web-font/";

@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  // src: url('https://fonts.gstatic.com/s/materialicons/v48/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2') format("woff2");

  src: url("#{$font-dir}flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2") format("woff2"),
  url("#{$font-dir}flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff") format("woff");
}

.material-icons {
  font-family: 'Material Icons';
  font-weight: normal;
  font-style: normal;
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;
}

Roboto-font.scss

$font-dir: "assets/fonts/roboto-font/web-font/";

@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 100;
  src: url("#{$font-dir}KFOkCnqEu92Fr1MmgVxIIzQ.woff") format("woff");
}

当使用

yarn serve

运行项目时,一切都正常。字体在网络选项卡中正确加载,但是在构建 Web 组件并使用“live server”在浏览器中加载它后,字体不会在网络选项卡中加载。

我能够让字体和图标正常工作的唯一方法是将链接标签添加到 index.html 文件中。但不在 Web 组件内(在 Shadow DOM 内)。

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>wc-demo</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />
    <link
      href="https://fonts.googleapis.com/css?family=Roboto&display=swap"
      rel="stylesheet"
    />
    <title>Document</title>
  </head>
  <body>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src=“./wc-demo.js"></script>
    <wc-demo></wc-demo>
  </body>
</html>

我希望能够了解如何在Web组件中包含字体,或者在HTML文件头部使用它是唯一的选择吗?

另外,我已经链接了一些类似的问题,这可能会帮助您帮助像我这样的许多人:

https://bugs.chromium.org/p/chromium/issues/detail?id=336876

在Polymer/Web组件中@font-face不起作用

https://robdodson.me/at-font-face-doesnt-work-in-shadow-dom/

为什么我的 Shadow DOM 中无法使用 Font Awesome?

1个回答

2

我不确定这个问题对作者是否仍然相关,但是:

我对这个主题进行了相当多的研究,发现:

没有办法从Web组件内部导入字体。 Web组件是自我隔离的。它们有自己的DOM树。这基本上意味着任何包含在父文档的head标签中的样式无法在Web组件内部使用

在Web组件内使用自定义字体的唯一方法是:

a) 禁用影子DOM。然后可以在父文件(例如head标签)中获取字体,并从Web组件内部使用这些字体。

b) 将字体定义包含在父级和Web组件中(这是代码重复)。

更新

经过一些实验,似乎我找到了解决方案。 在以下示例中,我使用的是StencilJS,这是专门用于Web组件开发的工具。

使用JavaScript / TypeScript可以获取阴影根元素的样式节点。 要访问此元素,我使用以下内容:

@Element() private element: HTMLElement;

来自StencilJS文档:

@Element()装饰器是在类实例中访问宿主元素的方法。这将返回一个HTMLElement实例,因此可以在此处使用标准DOM方法/事件。

现在我可以访问样式节点并在那里设置(导入)字体。将字体导入作为常规字符串加入样式中:

this.element.shadowRoot.querySelector('style').innerText += "@import url('https://fonts.googleapis.com/css2?family=Almendra+Display&family=Open+Sans:wght@200&display=swap');";
this.element.shadowRoot.querySelector('style').innerText += "p {font-family: 'Almendra Display', cursive;}";

这是我用Stencil构建的Web组件的解决方案。我强烈相信React也可以实现同样的效果。而且我认为这也可以在不使用任何框架的情况下完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接