Check burned-in caption contrast against WCAG 1.4.3 before rendering

WCAG 1.4.3 asks for 4.5:1 contrast on normal text and 3:1 on large text. Compute the ratio in Python, then set design.colors on a Sume caption job.

4 min readSume
All posts

W3C's Understanding page for success criterion 1.4.3 sets the minimum at 4.5:1 for normal text and 3:1 for large text, and says images of text are covered. A burned-in caption is drawn text, so a quick ratio check on your caption colours before you pay for a render is cheap insurance.

The thresholds

The page states the figures below. Treat them as the bar for the fill colour against whatever sits behind it.

WCAG 1.4.3 minimum contrast (read 2026-10-03)
TextMinimum ratio
Normal text4.5:1
Large text3:1

A ratio function you can run

This uses the relative luminance formula from WCAG. Pass the caption fill and the colour behind it; if the background is a card, use the card colour.

def lum(hex_color):
    rgb = [int(hex_color[i:i + 2], 16) / 255 for i in (1, 3, 5)]
    lin = [c / 12.92 if c <= 0.03928 else ((c + 0.055) / 1.055) ** 2.4 for c in rgb]
    return 0.2126 * lin[0] + 0.7152 * lin[1] + 0.0722 * lin[2]

def ratio(a, b):
    hi, lo = sorted((lum(a), lum(b)), reverse=True)
    return (hi + 0.05) / (lo + 0.05)

for fg, bg in [("#FFFFFF", "#000000"), ("#22D3EE", "#FFFFFF"), ("#FFE600", "#1A1A1A")]:
    r = ratio(fg, bg)
    print(fg, bg, round(r, 2), "ok" if r >= 4.5 else "fails 4.5:1")

Applying it to a Sume caption job

design.colors takes base, active, stroke, accent, accent_deep and card, as hex, rgb(), rgba() or transparent. Out-of-range values are a 400 at request time, so a bad look fails before it bills. design is not supported on punch or tiktok-green.

A white base on a dark card clears the bar easily. A bright active-word colour such as cyan against a white background does not, so check the active colour against the card, not just the base.

What this does not cover

Contrast against moving video behind the text varies frame to frame, which is why a solid card or a heavy stroke is safer than a bare fill. Run the check on the colours you control and review a rendered frame for the rest.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume