fonts - Web 组件 - 字体和材质图标不起作用 (@font-face)
问题描述
我正在尝试通过运行以下命令使用 vue cli 3 创建一个 Web 组件
vue-cli-service build --target wc --name wc-demo 'src/App.vue'
我面临在 Web 组件中加载字体和材质图标的问题。
我在App.vue 的style 标签内导入了 robots-font.scss和material-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");
}
使用运行项目时一切正常
纱线服务
. 字体在网络选项卡中加载正常,但在构建 Web 组件并使用“<strong>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
https://robdodson.me/at-font-face-doesnt-work-in-shadow-dom/
解决方案
我不确定这个问题是否仍然与作者相关,但是:
我对这个主题进行了相当多的研究,我发现:
无法从 Web 组件内部导入字体。Web 组件是自我隔离的。他们有自己的 DOM 树。这基本上意味着包含在父文档头部的任何样式在 web 组件中都将不可用。
在 web 组件中使用自定义字体的唯一方法是:
a)禁用影子域。然后,您可以在父文件(例如 head 标签)中获取字体并从 Web 组件内部使用这些字体。
b)包括字体定义:父组件和 web 组件(这是代码重复)。
更新
经过一些实验,我似乎找到了解决方案。在下面的示例中,我使用的是专门用于 Web 组件开发的工具StencilJS 。
使用 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 也可以达到同样的效果。而且我认为它也可以在不使用任何框架的情况下完成。
推荐阅读
- typescript - 使用 new() 签名声明接口,现在当我将接口用作对象时,它会为我提供函数属性?
- android - 如何在启动序列完成后创建启动服务的应用程序?
- sqlite - SQLite AUTOINCREMENT 非主键列
- javascript - JavaScript 自上一个日期/时间以来经过的时间
- azure - 首次应用后未输出 Terraform Azure mac 地址
- sails.js - Remove Fields when query at sails js
- python - 位数递减的最小数
- java - Remove multiple elements with multiple indexes from arraylist in java
- php - cURL error 8: Invalid Content-Length: value
- ios - 如何在单击关闭按钮时从数组中删除数据