Quick answer: Synthetic bold/italic changes glyph widths. Always re-measure with font.size(text) after toggling the style, or load a dedicated bold font file.
A UI lays out text using cached widths, then calls font.set_bold(True) for emphasis. The bold text overflows its box — the cached widths are for the regular weight.
Synthetic Styling Changes Metrics
set_bold and set_italic on a pygame Font apply a synthetic transform — faux bold smears each glyph slightly wider. Any width you measured before the toggle is now wrong.
Re-Measure After Toggling
font.set_bold(True)
w, h = font.size(text) # measure in the CURRENT style
surface = font.render(text, True, color)
Measure, then render, with the style already set. Don’t reuse a width from before the toggle.
Prefer a Real Bold Font
Synthetic bold is approximate and looks worse than a hand-designed bold weight. Load the actual bold file as a separate Font object:
regular = pygame.font.Font("Inter-Regular.ttf", 24)
bold = pygame.font.Font("Inter-Bold.ttf", 24)
Each has its own stable metrics — no toggling, no re-measuring surprises.
Cache Per Style
If you cache rendered text, key the cache on (text, style) — not just text. A regular and bold render of the same string are different surfaces.
Verifying
Bold emphasis text fits its box. Mixed regular/bold runs lay out correctly. Switching styles re-measures and never overflows.
“Style toggles change metrics. Re-measure after, or just load real weight files.”
For any polished UI, ship the actual font weights — synthetic bold/italic always looks a little off next to the real thing.