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.