Quick answer: After font.render(text, True, color), call surface.convert_alpha() on the result. Don’t set_colorkey on antialiased text — the fringe is partially-transparent and a colorkey makes it opaque.
Antialiased white text on a colored UI panel shows a halo of the text’s background color around each glyph. You set_colorkey on black to remove the background, but the antialias gradient kept some near-black pixels.
The Symptom
Text edges show fringes (often gray, blue, or whatever the text was rendered against). Particularly bad when text is rendered on a black background and blitted onto a non-black background.
The Fix
import pygame
font = pygame.font.Font(None, 36)
# Antialiased text with proper alpha
text = font.render("Hello, world", True, (255, 255, 255))
text = text.convert_alpha()
screen.blit(text, (10, 10))
convert_alpha gives the surface a per-pixel alpha channel. Antialiased edges blend correctly with whatever’s underneath.
What Not to Do
# Bad — fringes on edges
text = font.render("Hello", True, (255, 255, 255))
text.set_colorkey((0, 0, 0)) # colorkey is binary; antialias is gradient
Colorkey only removes exact-match pixels. Antialiased gradient pixels with alpha < 1 stay opaque, producing the fringe.
Performance
convert_alpha is fast. Calling it once per render is fine. For frequently-changing text (FPS counter), cache the rendered surface and only re-render when text actually changes.
Verifying
Render text on a non-black background. Edges should blend without halo. If you still see fringe, set_colorkey was applied and convert_alpha wasn’t.
“render(text, True, color).convert_alpha(). Edges clean.”
Related Issues
For Pygame sprite sort, see sprite sort. For mixer channels, see channel overflow.
convert_alpha. No fringe.