Raised by DrDrij in the v2.5.0 design review of QuantEcon/lecture-python-programming#363: "Spacing of inline <code> elements a little off, wide spacing between words but not enough padding before and after." Re-measured against the deployed Sphinx build, the theme reproduces code.literal within about 1% on every metric — including the padding, which Sphinx also sets to zero — and the wide inter-word gaps are the monospace space advance, which the Sphinx build has too. So there is no parity defect to fix. There is a design choice worth taking deliberately, because quantecon-book-theme ships the exact treatment DrDrij is describing as an opt-in mode that no lecture site has ever enabled.
What was measured
Sphinx column: the live page python-programming.quantecon.org/numpy.html as rendered, read from getComputedStyle in headless Chromium at 1440×1000 after document.fonts.ready. Theme column: the declarations at styles/quantecon.css:217-234 (.article :not(pre) > code), with the space advance measured for the resolved font stack in the same browser.
| Property |
Sphinx code.literal |
Theme .article :not(pre) > code |
Δ |
| font-size |
16.2px (.9rem of an 18px root) |
16px (1rem of a 16px root) |
−1.2% |
| prose size around it |
18px |
18px (styles/quantecon.css:314) |
— |
| font-family |
"Source Code Pro", monospace, and Source Code Pro is never loaded |
menlo, consolas, "DejaVu Sans Mono", monospace |
same rendered face |
| font-weight |
400 |
400 |
— |
| letter-spacing |
0.18px |
0.16px (0.01rem) |
−0.02px |
| colour |
rgb(175, 95, 95) |
#af5f5f |
— |
| padding |
0px, all four sides |
none declared anywhere |
— |
| background |
rgba(0, 0, 0, 0) |
none declared anywhere |
— |
| border |
0px none |
none declared anywhere |
— |
| space advance inside the literal |
9.91px |
9.80px |
−1.1% |
The wide inter-word gaps are the monospace space advance and nothing else. On the live Sphinx page a space inside code.literal measures 9.91px against 3.59px in the surrounding prose — a 2.76× ratio the theme reproduces at 9.80px. Letter-spacing contributes almost nothing: at 0.16px per gap it accounts for 2.89px of the 176.28px import numpy as np string, or 1.6%. Nothing narrows those gaps without narrowing the glyphs with them.
Source Code Pro is genuinely absent rather than merely unmeasurable: [...document.fonts] on the live page lists only Font Awesome, PT Serif, Source Sans Pro and the MathJax faces, and no @font-face for it exists in the 81KB quantecon-book-theme.css. The declared Source Code Pro, monospace therefore resolves to generic monospace, which measures the same 9.91px advance the theme's explicit stack lands on.
The theme's side of the padding row was checked two ways, not just by reading the rule: no declaration in styles/*.css puts padding, background or border on inline code, and @tailwindcss/typography's base styles add none either. Both builds render a bare literal.
Where the padding went, in Sphinx
Fetched from the deployed _static/styles/quantecon-book-theme.css. The boxed literal is defined:
cite,code,tt{background-color:#efefef;border:1px dotted #ccc;border-radius:2px;font-family:Source Code Pro,monospace;font-size:.9rem;font-style:normal;letter-spacing:.01rem;overflow-wrap:break-word;padding:0 2px}
and then switched off again for the case that actually occurs:
body:not(.inline-literal-box) code.literal{background-color:transparent;border:none;border-radius:0;padding:0}
inline-literal-box appears exactly once in that stylesheet — in the rule above, which disables the box — and nowhere in the served markup: every lecture page renders a bare <body> with className === "". So the disabling rule always matches, at (0,2,2) against the box rule's (0,0,1), and the box has never drawn on a QuantEcon lecture site. The padded, tinted, dotted-border literal DrDrij is asking for is not a new design. It is the Sphinx theme's own alternate mode, built and left unused, and under the recorded stance that makes it a live option rather than a closed question.
What adopting it actually costs
Not the CSS. The declarations already exist in both codebases, and the rendered difference is two pixels of horizontal padding, a grey ground and a dotted hairline. The cost is contrast and dark mode.
Light mode fails as written. #af5f5f is 4.54:1 on white — already only just over the AA 4.5:1 minimum, and flagged as such at styles/quantecon.css:83. On the #efefef ground it drops to 3.95:1. Adopting the box means darkening the literal colour or lightening the ground, in both stacks, so the two builds do not diverge on the colour while diverging on nothing else.
Dark mode is untested rather than absent. The Sphinx sheet does carry a dark treatment for the box:
body.dark-theme cite,body.dark-theme code,body.dark-theme tt{background-color:var(--qe-dark-surface);border-color:var(--qe-dark-border);color:var(--qe-dark-inline-code)}
with --qe-dark-surface:#252540 and --qe-dark-border:#3a3a5c. That rule is (0,1,2) and the disabling rule is (0,2,2), so the box is off in dark mode too and those values have never been displayed to a reader either. This theme has no counterpart for them: its dark block at styles/quantecon.css:99-103 defines only --qe-literal-color, --qe-link-color and --qe-link-hover-color. Adopting means shipping a dark treatment neither build has ever rendered, and introducing the two surface tokens here. The dark literal colour itself is fine — #d78787 on #252540 is 5.44:1.
Options 2 and 3 also move every visual baseline that contains inline code, across all four platform sets (24 PNGs under tests/visual/__snapshots__), and a two-pixel padding change is well inside the 1% maxDiffPixelRatio at tests/visual/theme.spec.ts:34, so the local refresh needs --update-snapshots=all and the CI set needs an /update-snapshots comment.
Options
- Accept as is. The theme reproduces what the lecture sites actually render, to within 1% on every metric of this rule. Reply to DrDrij with the measurements and record the decision. Costs nothing and moves no baseline. The right answer if the goal is that a reader cannot tell the two builds apart during the migration.
- Adopt the boxed literal in both builds. Answers DrDrij directly, with values that already exist in both codebases, and keeps the builds identical. Costs: a contrast pass on the literal colour against the new ground in both stacks, a dark-mode ground and border this theme has no tokens for, a matching change in
quantecon-book-theme, and a baseline refresh here.
- Adopt it in this theme only. Cheapest to ship and it still needs the contrast and dark-mode work, but it makes the mystmd build visibly unlike the sites it replaces, on an element that appears in nearly every paragraph, for the whole migration window.
The measurements do not choose between these. What chooses is whether a designer wants the box now that it is clear nobody has ever seen it, and whether the contrast work is worth doing to get it.
Two things to confirm with DrDrij before deciding
Which viewport he reviewed at. Below 992px the Sphinx root steps down to 16px (@media(min-width:992px){html{font-size:18px}}, confirmed at 900px: root 16px, literal 14.4px), while this theme holds a flat 16px literal. That is an 11% difference at narrow widths, produced by a media query rather than by this rule, and the theme's flat sizing is deliberate — a px root is a WCAG 1.4.4 problem, which is why the Sphinx theme has to ship font-plus/font-minus controls to compensate (see the UNITS note at styles/quantecon.css:55-74). If he reviewed in a narrow window he saw a real difference, and it is not the one this issue is about. At desktop width he did not.
Which build his screenshot came from. The sentence in it — "After import numpy as np we have access to these attributes via the syntax np.attribute" — does not appear on the live Sphinx numpy.html. Fetching that page and searching for np.attribute, these attributes and import numpy as np returns zero matches for all three. So the comparison may not have been like with like, and it is worth knowing what the reference image was before reading anything into it.
A correction to make while anyone is in this rule
The comment at styles/quantecon.css:220-224 says the monospace family comes from "Tailwind's preflight and JupyterLab's stylesheet". Only the second half is doing any work. Tailwind's preflight sets code,kbd,samp,pre{font-family:theme('fontFamily.mono', …)} at (0,0,1), and thebe-core.css vendors a JupyterLab rule at the same (0,0,1):
tt,
code,
kbd,
samp,
pre {
font-family: var(--jp-code-font-family);
font-size: var(--jp-code-font-size);
line-height: var(--jp-code-line-height);
}
app/root.tsx loads the Tailwind bundle at line 158 and thebe-core.css at line 159, so on equal specificity the later sheet wins and the resolved family is --jp-code-font-family-default = menlo, consolas, "DejaVu Sans Mono", monospace (node_modules/thebe-core/dist/lib/thebe-core.css:108-113, rule at :263-271). That is a happy accident rather than a mistake — Chrome's generic monospace on macOS resolves to Menlo too, which is why the measured advances match — but the comment records the wrong cause, and the same thebe rule is why --jp-code-font-size: 13px lands on inline <code> outside .article (article literals are safe: .article :not(pre) > code is (0,1,2) and wins).
Raised by DrDrij in the v2.5.0 design review of QuantEcon/lecture-python-programming#363: "Spacing of inline
<code>elements a little off, wide spacing between words but not enough padding before and after." Re-measured against the deployed Sphinx build, the theme reproducescode.literalwithin about 1% on every metric — including the padding, which Sphinx also sets to zero — and the wide inter-word gaps are the monospace space advance, which the Sphinx build has too. So there is no parity defect to fix. There is a design choice worth taking deliberately, becausequantecon-book-themeships the exact treatment DrDrij is describing as an opt-in mode that no lecture site has ever enabled.What was measured
Sphinx column: the live page
python-programming.quantecon.org/numpy.htmlas rendered, read fromgetComputedStylein headless Chromium at 1440×1000 afterdocument.fonts.ready. Theme column: the declarations atstyles/quantecon.css:217-234(.article :not(pre) > code), with the space advance measured for the resolved font stack in the same browser.code.literal.article :not(pre) > code.9remof an 18px root)1remof a 16px root)styles/quantecon.css:314)"Source Code Pro", monospace, and Source Code Pro is never loadedmenlo, consolas, "DejaVu Sans Mono", monospace0.01rem)rgb(175, 95, 95)#af5f5frgba(0, 0, 0, 0)0px noneThe wide inter-word gaps are the monospace space advance and nothing else. On the live Sphinx page a space inside
code.literalmeasures 9.91px against 3.59px in the surrounding prose — a 2.76× ratio the theme reproduces at 9.80px. Letter-spacing contributes almost nothing: at 0.16px per gap it accounts for 2.89px of the 176.28pximport numpy as npstring, or 1.6%. Nothing narrows those gaps without narrowing the glyphs with them.Source Code Pro is genuinely absent rather than merely unmeasurable:
[...document.fonts]on the live page lists only Font Awesome, PT Serif, Source Sans Pro and the MathJax faces, and no@font-facefor it exists in the 81KBquantecon-book-theme.css. The declaredSource Code Pro, monospacetherefore resolves to generic monospace, which measures the same 9.91px advance the theme's explicit stack lands on.The theme's side of the padding row was checked two ways, not just by reading the rule: no declaration in
styles/*.cssputspadding,backgroundorborderon inline code, and@tailwindcss/typography's base styles add none either. Both builds render a bare literal.Where the padding went, in Sphinx
Fetched from the deployed
_static/styles/quantecon-book-theme.css. The boxed literal is defined:and then switched off again for the case that actually occurs:
inline-literal-boxappears exactly once in that stylesheet — in the rule above, which disables the box — and nowhere in the served markup: every lecture page renders a bare<body>withclassName === "". So the disabling rule always matches, at (0,2,2) against the box rule's (0,0,1), and the box has never drawn on a QuantEcon lecture site. The padded, tinted, dotted-border literal DrDrij is asking for is not a new design. It is the Sphinx theme's own alternate mode, built and left unused, and under the recorded stance that makes it a live option rather than a closed question.What adopting it actually costs
Not the CSS. The declarations already exist in both codebases, and the rendered difference is two pixels of horizontal padding, a grey ground and a dotted hairline. The cost is contrast and dark mode.
Light mode fails as written.
#af5f5fis 4.54:1 on white — already only just over the AA 4.5:1 minimum, and flagged as such atstyles/quantecon.css:83. On the#efefefground it drops to 3.95:1. Adopting the box means darkening the literal colour or lightening the ground, in both stacks, so the two builds do not diverge on the colour while diverging on nothing else.Dark mode is untested rather than absent. The Sphinx sheet does carry a dark treatment for the box:
with
--qe-dark-surface:#252540and--qe-dark-border:#3a3a5c. That rule is (0,1,2) and the disabling rule is (0,2,2), so the box is off in dark mode too and those values have never been displayed to a reader either. This theme has no counterpart for them: its dark block atstyles/quantecon.css:99-103defines only--qe-literal-color,--qe-link-colorand--qe-link-hover-color. Adopting means shipping a dark treatment neither build has ever rendered, and introducing the two surface tokens here. The dark literal colour itself is fine —#d78787on#252540is 5.44:1.Options 2 and 3 also move every visual baseline that contains inline code, across all four platform sets (24 PNGs under
tests/visual/__snapshots__), and a two-pixel padding change is well inside the 1%maxDiffPixelRatioattests/visual/theme.spec.ts:34, so the local refresh needs--update-snapshots=alland the CI set needs an/update-snapshotscomment.Options
quantecon-book-theme, and a baseline refresh here.The measurements do not choose between these. What chooses is whether a designer wants the box now that it is clear nobody has ever seen it, and whether the contrast work is worth doing to get it.
Two things to confirm with DrDrij before deciding
Which viewport he reviewed at. Below 992px the Sphinx root steps down to 16px (
@media(min-width:992px){html{font-size:18px}}, confirmed at 900px: root 16px, literal 14.4px), while this theme holds a flat 16px literal. That is an 11% difference at narrow widths, produced by a media query rather than by this rule, and the theme's flat sizing is deliberate — a px root is a WCAG 1.4.4 problem, which is why the Sphinx theme has to ship font-plus/font-minus controls to compensate (see the UNITS note atstyles/quantecon.css:55-74). If he reviewed in a narrow window he saw a real difference, and it is not the one this issue is about. At desktop width he did not.Which build his screenshot came from. The sentence in it — "After
import numpy as npwe have access to these attributes via the syntaxnp.attribute" — does not appear on the live Sphinxnumpy.html. Fetching that page and searching fornp.attribute,these attributesandimport numpy as npreturns zero matches for all three. So the comparison may not have been like with like, and it is worth knowing what the reference image was before reading anything into it.A correction to make while anyone is in this rule
The comment at
styles/quantecon.css:220-224says the monospace family comes from "Tailwind's preflight and JupyterLab's stylesheet". Only the second half is doing any work. Tailwind's preflight setscode,kbd,samp,pre{font-family:theme('fontFamily.mono', …)}at (0,0,1), andthebe-core.cssvendors a JupyterLab rule at the same (0,0,1):app/root.tsxloads the Tailwind bundle at line 158 andthebe-core.cssat line 159, so on equal specificity the later sheet wins and the resolved family is--jp-code-font-family-default=menlo, consolas, "DejaVu Sans Mono", monospace(node_modules/thebe-core/dist/lib/thebe-core.css:108-113, rule at:263-271). That is a happy accident rather than a mistake — Chrome's genericmonospaceon macOS resolves to Menlo too, which is why the measured advances match — but the comment records the wrong cause, and the same thebe rule is why--jp-code-font-size: 13pxlands on inline<code>outside.article(article literals are safe:.article :not(pre) > codeis (0,1,2) and wins).