shadow dom中font-family不继承不是bug,是设计使然:虽属可继承属性,但仅当宿主元素显式声明该值时才穿透边界;否则影子树内元素使用默认字体,需通过:host{font-family:inherit}显式继承。

Shadow DOM里font-family为什么不继承
不是bug,是浏览器明确限制:虽然font-family属于CSS可继承属性,但Shadow DOM只让部分继承链“穿透”边界,且前提是宿主元素**自身显式声明了该值**。如果宿主只是个空<div>,哪怕<code>body设了font-family: "Inter",影子树里的<p></p>照样用默认字体。
常见错误现象:shadowRoot.innerHTML = '<p>Hello</p>'后文字没变字体;DevTools里看到“inherited from body”,但实际没生效——那只是UI提示误导,不是真实继承链。
- 必须在Shadow Root内部的
<style></style>中写:host { font-family: inherit; } - 宿主元素本身得有明确字体声明,比如
<my-card style="font-family: 'Inter', sans-serif;"></my-card> - 别依赖
html或body全局样式,它们不作用于shadow tree
Web字体(@font-face)在Shadow DOM中怎么声明才有效
@font-face规则必须出现在主文档的CSSOM中,或通过adoptedStyleSheets注入到Shadow Root,写在shadowRoot.innerHTML里的@font-face完全被忽略——浏览器根本不解析它。
容易踩的坑:shadowRoot.innerHTML = '<style>@font-face { font-family: "MyFont"; src: url("./font.woff2"); }</style>',这行代码执行后,document.fonts.check('16px "MyFont"')返回false。
- 正确做法:把
@font-face定义在主文档的<style></style>里,或用new CSSStyleSheet()创建后加入element.shadowRoot.adoptedStyleSheets - 字体路径始终相对于主文档URL,不是JS文件位置,也不是shadow tree结构
- 若用
adoptedStyleSheets,需确保浏览器支持(Chrome 73+、Safari 16.4+)
如何可靠检测自定义字体在Shadow DOM中是否加载完成
font-display: swap只控制渲染策略,不提供加载完成信号。直接监听DOMContentLoaded或window.onload也不行——字体可能还在缓存校验或网络请求中。
关键点在于:document.fonts.load()必须传完整描述,否则静默失败;document.fonts.ready不会主动触发加载,只等待已声明字体就绪。
- 先调用
document.fonts.load("400 16px 'Inter'"),注意引号、字重、字号都要匹配@font-face声明 - 再链式等待
document.fonts.ready,不能单独await document.fonts.ready - 在Shadow DOM中使用时,确保宿主或
:host已应用该字体族,否则load()可能不触发实际下载
图片、SVG等资源路径在Shadow DOM中如何解析
所有相对路径(src、url())都基于document.baseURI,也就是当前HTML文档的URL,和Shadow DOM挂载位置、JS文件路径、模板所在位置完全无关。
典型误判:用template.innerHTML加载含<img src="icon.svg">的片段,以为路径相对于模板HTML文件;实际仍从主页面URL开始解析。
- 动态生成的Shadow DOM若挂载在
<iframe></iframe>里,路径则相对于iframe.src,不是父页面 -
<link rel="preload" as="font">必须带crossorigin(无值),否则CORS失败且无回退,控制台可能只报FOIT(Flash of Invisible Text) - 避免在
@import或url()中用./相对路径,除非你确认主文档baseURI指向预期目录
baseURI和字体声明位置稍有偏差,就会导致文字回退、图标404、主题色失效——这些问题往往要到上线后才暴露,且难以复现。











