Skip to content

MathJax √ radical bar has vertical+horizontal gap from √ glyph (AnkiDroid only; MathJax 3 CHTML) #20776

@salmon-21

Description

@salmon-21

Checked for duplicates?

  • Most related prior issue is MathJax displays differently in newest version #9002 (closed 2021) but that was about general MathJax rendering differences. This one is specifically about the √ radical bar not connecting to the √ glyph.
  • Related forum thread (no resolution, auto-closed): MathJax looks bunched up — same class of symptom (MathJax HTML renderer quirks on AnkiDroid vs Desktop). Moderator characterizes these as MathJax HTML renderer issues rather than AnkiDroid-specific, which is consistent with the diagnosis below.

Does it also happen in the desktop version?

  • Does NOT occur on Anki Desktop (Qt WebEngine). Only AnkiDroid (Android WebView).

Steps to reproduce

  1. Create a card with \( \sqrt{a^2} \) (or any \sqrt{...})
  2. View on AnkiDroid and on Anki Desktop side by side

Expected

Horizontal bar of √ touches the top-right of the √ glyph, as on Desktop.

Actual

On AnkiDroid, the bar sits a few px above the √ tail and a few px right of where it should meet the glyph tip. A visible gap appears between the glyph and the bar.

Screenshot

Before (no fix — visible gap) After (with CSS workaround)
before after

Diagnosis (via chrome://inspect)

  • MathJax: 3.2.2, CHTML output (jax="CHTML")
  • DOM structure: <mjx-sqrt><mjx-surd><mjx-c class="mjx-c221A"></mjx-c></mjx-surd><mjx-box style="padding-top: 0.123em"> — the bar is border-top of mjx-box
  • surd.top === box.top and surd.right === box.left per getBoundingClientRect()layout is 0-gap, the gap is purely visual
  • Computed border-top: ~2.78px solid currentColor
  • Fonts MJXZERO and MJXTEX both loaded — no font-loading race
  • Root cause: MJX-TEX font's glyph bearing (blank space inside the √ character's em box) is rasterized with more offset by Android WebView than by Qt WebEngine. MathJax 3 places the bar at the top of the em box; when the glyph's visible top is below that, a gap appears.

Additional notes on MathJax 2 config dead code

Many card templates carry legacy

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({ "HTML-CSS": { preferredFont: "Noto Sans Math", webFont: "Noto Sans Math", ... } });
</script>

blocks. These are silently ignored by MathJax 3 (and any CSS @font-face / mjx-c { font-family: ... } overrides cause metrics mismatches with MJX-TEX's internal metric tables). Not a bug — just something that newcomers will find confusing.

Workaround (tested, works)

CSS on the affected note types:

html.mobile-webview mjx-sqrt > mjx-box {
    margin-top: 3px !important;
    margin-left: -3px !important;
}

Tiny UA-detect script at the top of each Front template:

<script>if(/Android|iPhone|iPad|iPod/i.test(navigator.userAgent))document.documentElement.classList.add("mobile-webview");</script>

Important: @media (hover: none) and (pointer: coarse) does not match on AnkiDroid WebView (confirmed via matchMedia(...).matches === false), so a simple media query won't work — the UA-based class is needed.

The 3px / -3px values are a compromise — the required offset varies slightly per card because MathJax uses different √ size variants (MJXTEX-S1..S4) for different radicand heights.

Expected resolution path

Likely fixed by upstream Anki's adoption of MathJax 4, which allows switching to mathjax-newcm or mathjax-stix2 fonts — different fonts may not have the same bearing mismatch in Android WebView.

Tracking upstream:

Debug info

AnkiDroid 2.23.3 (or current), Android WebView (Chromium-based). Reproduces on multiple Android versions.


Filing for visibility / as a test case. No urgent fix needed — local workaround works. Feel free to close as wontfix or dupe-of-mathjax-4-migration if appropriate.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions