我有一个带有 Shadow DOM 的 HTML 5 WebComponent,它显示的内容必须根据组件中显示的内容类型加载样式。样式表列表是从服务器获取的。
我可以像这样加载样式表:
for (const style of styles) {
const stylesheet = document.createElement('link');
stylesheet.setAttribute('rel', 'stylesheet');
stylesheet.setAttribute('href', style);
stylesheet.setAttribute('type', 'text/css');
this.root.appendChild(stylesheet);
}
Run Code Online (Sandbox Code Playgroud)
但是,样式表有时还包含@font-face未添加到组件中的规则。浏览器永远不会创建对规则中字体引用的请求@font-face。如何动态加载这些规则?
事实证明,@font-face截至 2020 年 9 月,浏览器不支持在影子 DOM 中加载 CSS 规则。不过,Chrome 团队似乎正在努力解决这个问题。
我采取的方法是在动态创建的样式表中查找@font-face规则,稍微修改它们以使相对路径正常工作,然后<head>使用脚本将它们添加到页面中。如果将@font-face规则添加到 head和Shadow DOM,则会加载并应用字体。
这是代码:
for (const style of styles) { // styles is an array of urls
const stylesheet = document.createElement('link');
stylesheet.setAttribute('rel', 'stylesheet');
stylesheet.setAttribute('href', style);
stylesheet.setAttribute('type', 'text/css');
stylesheet.onload = (event) => {
for (
let i = 0;
i < event.currentTarget.sheet.cssRules.length;
i++
) {
if (event.currentTarget.sheet.cssRules[i].type == 5) { // type 5 is @font-face
const split = style.split('/');
const stylePath = split
.slice(0, split.length - 1)
.join('/');
let cssText =
event.currentTarget.sheet.cssRules[i].cssText;
cssText = cssText.replace(
// relative paths
/url\s*\(\s*[\'"]?(?!((\/)|((?:https?:)?\/\/)|(?:data\:?:)))([^\'"\)]+)[\'"]?\s*\)/g,
`url("${stylePath}/$4")`
);
const st = document.createElement('style');
st.appendChild(document.createTextNode(cssText));
document
.getElementsByTagName('head')[0]
.appendChild(st);
}
}
};
this.root.appendChild(stylesheet);
}
Run Code Online (Sandbox Code Playgroud)
它在 Edge 85(基于 Chromium)上运行良好。
| 归档时间: |
|
| 查看次数: |
2643 次 |
| 最近记录: |