Skip to content

fix(reader): 移动端 useBookFonts 不应强制阅读器字体到 body - #756

Open
k6G52m4Dz75W wants to merge 3 commits into
codedogQBY:mainfrom
k6G52m4Dz75W:fix/mobile-usebookfonts-clean
Open

fix(reader): 移动端 useBookFonts 不应强制阅读器字体到 body#756
k6G52m4Dz75W wants to merge 3 commits into
codedogQBY:mainfrom
k6G52m4Dz75W:fix/mobile-usebookfonts-clean

Conversation

@k6G52m4Dz75W

@k6G52m4Dz75W k6G52m4Dz75W commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

问题

移动端阅读器(reader.template.html)的 baseStyles 中有一条无条件规则:

:root:not(.vrtl):not(.vltr),
:root:not(.vrtl):not(.vltr) body {
  font-family: var(--readany-font-family) !important;
}

即使 useBookFonts 处于启用状态(默认开启),这条规则仍把阅读器字体强制应用到 body,覆盖书在 body 上指定的 font-family。因此 epub 嵌入字体在移动端从不生效(很多 epub 在 body 上指定字体)。

桌面端已正确处理(useBookFonts 启用时用 :where(html) 零特异性兜底,书字体优先),移动端未对齐。

修复

对齐桌面端实现(FoliateViewer.tsx):

  • useBookFonts 启用(默认):只注入 :where(html) { font-family: var(--readany-font-family); } —— 零特异性,只影响 htmlbody 继承 html 字体,书在 html/body/任何元素上指定的字体优先
  • useBookFonts 关闭:强制 html, body + 所有后代使用阅读器字体。

reader.htmlbuild:reader 在 prebuild 时自动生成,故本次仅改动模板源码 reader.template.html

验证

  • headless(Chromium)实测:书 body { font-family: "BookEmbeddedFont" } 时,
    • 修复前:"Reader Font", sans-serif(阅读器字体覆盖书)
    • 修复后:BookEmbeddedFont, serif书嵌入字体生效
  • Android 模拟器实测useBookFonts 启用时书字体正常渲染。

说明

  • 这是对已合并的 useBookFonts 功能的移动端 bug 修复,仅改动 1 个文件(reader.template.html)。

Follow-up(代码字体层):body 字体修复之外,pre/code/kbd/samp 的等宽规则原先也是无条件 !important——useBookFonts 开启时书内嵌代码字体同样渲染不出来。现改为与正文同一模式随开关切换:开启时 :where() 零特异性让位,关闭时 html body :is() (0,0,3) + !important 确保覆盖(裸 !important 会输给书内 body pre { !important },特异性在 important 之间仍然生效)。已在无头 Chromium 7 场景验证层叠结果,方案对齐 readest#6047 的代码字体加固。

The mobile reader.template.html always emitted an unconditional
':root:not(.vrtl):not(.vltr) body { font-family: var(--readany-font-family)
!important }' in baseStyles. Even with useBookFonts enabled (default), this
pinned the reader font on body and overrode the book's own font-family set on
body, so embedded EPUB fonts never rendered on mobile.

Align with the desktop implementation: when useBookFonts is on, emit only a
zero-specificity ':where(html)' fallback so body INHERITS the reader font but
the book's own font-family (on html, body, or any element) wins where
specified. When disabled, force reader font on html/body and every descendant.

reader.html is regenerated by build:reader during prebuild, so only the
template source changes here.

Verified on Android emulator: book fonts now render with useBookFonts enabled.
The pre/code/kbd/samp monospace rule was unconditional !important on
both ends, so with useBookFonts enabled (default) a book's own code
font — e.g. an embedded @font-face on pre — never rendered, the same
class of bug PR codedogQBY#756 fixed for the body font.

The monospace rule now swaps sides with the same toggle:

- useBookFonts on: :where(pre, code, kbd, samp) at zero specificity
  with no !important, so any book declaration wins; without one the
  monospace chain still applies as the fallback.
- useBookFonts off (override): html body :is(pre, code, kbd, samp) with
  !important. !important alone is not enough: specificity still breaks
  ties between important author declarations, so a plain
  'pre, code, kbd' at (0,0,1) loses to an authored
  'body pre { ... !important }' at (0,0,2); (0,0,3) outranks both.

Mirrors readest#6047 (code-font cascade hardening) on top of the
appearance-branch :where approach. Verified the resolved cascade in
headless Chromium across 7 scenarios: book code/body fonts win when
honored, fallbacks still apply, and the override beats authored
!important rules at equal and higher specificity on both ends.
@k6G52m4Dz75W
k6G52m4Dz75W force-pushed the fix/mobile-usebookfonts-clean branch from cf03cf2 to 1e1e521 Compare September 11, 2026 15:56
… contract test

Addresses the 6 findings from the OCR review of the code-font work:

- Restore the horizontal-writing guard (:root:not(.vrtl):not(.vltr)) on
  the forced overrides in the mobile template. The pre-existing rules
  were scoped to horizontal documents and the vertical branch must keep
  its own behavior — the unscoped 'html, body' / 'body *' rules from the
  previous commit leaked into vertical mode (OCR medium).
- Inner code/kbd/samp inside a pre now get a zero-specificity
  'font-family: inherit' instead of just being excluded from the
  monospace fallback: the UA stylesheet's own 'code { font-family:
  monospace }' is a direct declaration, which beats inheritance, so
  exclusion alone still cut '<pre><code>' off from the book's font
  declared on pre (OCR low, verified in a real engine). Any author
  declaration on the element still wins the inherit.
- Add usebook-fonts-contract.test.ts pinning the rule shapes for both
  toggle states across the template, the generated artifact, and the
  desktop generator — the triplicated recipe previously had no
  automated coverage and could drift silently (OCR low x2).

Verified in headless Chromium: 15 scenarios pass covering both toggle
states, inner-code inheritance, UA-default interception, the vertical
guard, and override-vs-authored-important at equal and higher
specificity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant