From 0fb42c339e52693294a3e6775594ce6ce07e4fad Mon Sep 17 00:00:00 2001 From: Ciinz-04 <330019480+Ciinz-04@users.noreply.github.com> Date: Fri, 2 Oct 2026 10:15:25 +0800 Subject: [PATCH] Inherit the editor font in the highlight overlay The element inside #editor-highlight took font-family: monospace from the user-agent stylesheet instead of the stack set on the overlay. Safari on macOS resolves the textarea's ui-monospace to SF Mono, so the two layers used different fonts, and the taller line box moved the painted text away from the caret a little more on every line. Other browsers skip ui-monospace and can land on the same font for both. --- tests/browser/editor-pipeline.test.js | 30 +++++++++++++++++++++++++-- web/styles.css | 7 +++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/browser/editor-pipeline.test.js b/tests/browser/editor-pipeline.test.js index fe667416..80991953 100644 --- a/tests/browser/editor-pipeline.test.js +++ b/tests/browser/editor-pipeline.test.js @@ -1,5 +1,5 @@ -// A browser-level pin for the bracket auto-close pipeline in web/editor.js -// and web/interview.js. +// A browser-level pin for the editor pipeline in web/editor.js and +// web/interview.js: bracket auto-close, and the overlay that paints its text. import { after, before, test } from "node:test"; import assert from "node:assert/strict"; @@ -154,3 +154,29 @@ test("Backspace right after an auto-closed pair removes both characters, in a re await page.close(); } }); + +test("the highlight overlay resolves the textarea's font metrics, in a real browser", async (t) => { + const ctx = await editorPage(t); + if (!ctx) return; + const { page } = ctx; + try { + // The overlay paints the glyphs the textarea positions. Any metric of the + // shared #editor, #editor-highlight rule that resolves on its own + // moves the painted text away from the caret, a little more every line. + const [editor, overlay] = await page.evaluate(() => + ["#editor", "#editor-highlight code"].map((selector) => { + const style = getComputedStyle(document.querySelector(selector)); + return { + fontFamily: style.fontFamily, + fontSize: style.fontSize, + lineHeight: style.lineHeight, + fontWeight: style.fontWeight, + letterSpacing: style.letterSpacing, + }; + }), + ); + assert.deepEqual(overlay, editor); + } finally { + await page.close(); + } +}); diff --git a/web/styles.css b/web/styles.css index 5e6af1e9..90fd02b0 100644 --- a/web/styles.css +++ b/web/styles.css @@ -899,6 +899,13 @@ p { overflow: hidden; } +/* The user-agent stylesheet gives its own monospace family, which + beats the inherited stack and paints the overlay in a different font from + the textarea, so the text drifts from the caret line by line. */ +#editor-highlight code { + font: inherit; +} + #editor-lines { position: absolute; inset: 0 auto 0 0;