Color Contrast Checker
Kontrollera WCAG AA- och AAA-kontrastförhållande mellan text- och bakgrundsfärg
Förgrundsfärg (text)
Bakgrundsfärg
Stort textexempel (18px fetstil)
Normalt textexempel — så här kommer din brödtext att se ut mot den bakgrundsfärg du valt.
Kontrastförhållande
14.63:1
WCAG-kompatibilitet
Godkänd
Normal AA
Godkänd
Normal AAA
Godkänd
Stor AA
Godkänd
Stor AAA
WCAG AA — Normal text: 4.5:1, Stor text (18px+ eller 14px fetstil): 3:1
WCAG AAA — Normal text: 7:1, Stor text (18px+ eller 14px fetstil): 4.5:1
Vad är kontrastkontroll av färger?
Kontrastkontroll av färger mäter luminansskillnaden mellan en förgrundsfärg (vanligtvis text) och en bakgrundsfärg, och uttrycker resultatet som ett förhållande. Ett förhållande på 1:1 innebär att färgerna är identiska; 21:1 är maximum och representerar svart på vitt eller vice versa. Web Content Accessibility Guidelines (WCAG), publicerade av W3C, definierar de minsta kontrastförhållanden som text måste uppfylla för att personer med nedsatt syn eller färgseendedefekter ska kunna läsa den.
Formeln för kontrastförhållande kommer från WCAG 2.x och bygger på relativ luminans — ett mått på hur ljus en färg upplevs av det mänskliga ögat. Relativ luminans beräknas genom att linjärisera varje sRGB-kanal (ta bort gamma) och vikta kanalerna enligt ITU-R BT.709-koefficienterna: 0,2126 för rött, 0,7152 för grönt och 0,0722 för blått. Grönt bidrar mest eftersom ögat är känsligast för grönt ljus. Förhållandet beräknas sedan som (L1 + 0,05) / (L2 + 0,05), där L1 är den ljusare färgens luminans.
WCAG definierar två överensstämmelsenivåer. Nivå AA kräver ett kontrastförhållande på minst 4,5:1 för normalstorlek text och 3:1 för stor text (18px eller mer, eller 14px fetstil). Nivå AAA höjer ribban till 7:1 respektive 4,5:1. WCAG 2.1 introducerade också Framgångskriterium 1.4.11, som kräver ett förhållande på 3:1 för icke-textuella UI-komponenter som kanter, ikoner och fokusindikatorer.
Varför använda denna kontrastkontroll?
Att kontrollera kontrast med ögat är opålitligt. Färger som ser distinkta ut på din kalibrerade skärm kan smälta samman på en billig laptop, i direkt solljus, eller för någon med deuteranopi. Ett numeriskt förhållande tar bort gissningarna och ger dig ett godkänd/underkänd-utslag mot WCAG-standarden.
Användningsområden för kontrastkontroll
WCAG-krav på kontrastförhållande
Tabellen nedan sammanfattar de minsta kontrastförhållanden som krävs av WCAG 2.1 för olika innehållstyper och överensstämmelsenivåer. Stor text definieras som 18px (24 CSS-pixlar) eller mer vid normal vikt, eller 14px (18,66 CSS-pixlar) eller mer vid fetstil.
| Nivå | Minförhållande | Gäller för | Anmärkning |
|---|---|---|---|
| AA Normal text | 4.5 : 1 | Body text, paragraphs, labels | Minimum for most UI text |
| AA Large text | 3.0 : 1 | Text >= 18px, or >= 14px bold | Minimum for headings |
| AA UI components | 3.0 : 1 | Borders, icons, focus indicators | Non-text contrast (WCAG 1.4.11) |
| AAA Normal text | 7.0 : 1 | Body text at highest standard | Enhanced readability |
| AAA Large text | 4.5 : 1 | Large text at highest standard | Enhanced for headings |
Luminans, AA och AAA förklarade
Beräkningen av kontrastförhållande har tre steg: beräkna luminans för varje färg, härleda förhållandet och jämföra det mot WCAG-trösklarna.
Kodexempel
Beräkna WCAG-kontrastförhållanden programmatiskt. Varje exempel implementerar formeln för relativ luminans från WCAG 2.x och beräkningen av kontrastförhållande. Samma par med svart-på-vitt och indigo-på-vitt testas för jämförelse.
// Calculate relative luminance per WCAG 2.x (sRGB)
function luminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c /= 255
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
})
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs
}
// Contrast ratio between two RGB colors
function contrastRatio(fg, bg) {
const l1 = luminance(...fg)
const l2 = luminance(...bg)
const lighter = Math.max(l1, l2)
const darker = Math.min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
contrastRatio([0, 0, 0], [255, 255, 255]) // -> 21.0
contrastRatio([99, 102, 241], [255, 255, 255]) // -> 3.95
contrastRatio([29, 78, 216], [255, 255, 255]) // -> 6.06 (AA pass)def luminance(r: int, g: int, b: int) -> float:
"""Relative luminance per WCAG 2.x, ITU-R BT.709 coefficients."""
channels = []
for c in (r, g, b):
c /= 255
channels.append(c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4)
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2]
def contrast_ratio(fg: tuple, bg: tuple) -> float:
l1 = luminance(*fg)
l2 = luminance(*bg)
lighter, darker = max(l1, l2), min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
print(f"{contrast_ratio((0, 0, 0), (255, 255, 255)):.2f}") # -> 21.00
print(f"{contrast_ratio((99, 102, 241), (255, 255, 255)):.2f}") # -> 3.95
# Check WCAG AA for normal text
ratio = contrast_ratio((29, 78, 216), (255, 255, 255))
print(f"{ratio:.2f} — {'AA pass' if ratio >= 4.5 else 'AA fail'}") # -> 6.06 — AA passpackage main
import (
"fmt"
"math"
)
func linearize(c float64) float64 {
c /= 255
if c <= 0.04045 {
return c / 12.92
}
return math.Pow((c+0.055)/1.055, 2.4)
}
func luminance(r, g, b int) float64 {
return 0.2126*linearize(float64(r)) +
0.7152*linearize(float64(g)) +
0.0722*linearize(float64(b))
}
func contrastRatio(fgR, fgG, fgB, bgR, bgG, bgB int) float64 {
l1 := luminance(fgR, fgG, fgB)
l2 := luminance(bgR, bgG, bgB)
lighter := math.Max(l1, l2)
darker := math.Min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
func main() {
ratio := contrastRatio(0, 0, 0, 255, 255, 255)
fmt.Printf("%.2f\n", ratio) // -> 21.00
ratio = contrastRatio(29, 78, 216, 255, 255, 255)
fmt.Printf("%.2f\n", ratio) // -> 6.06 (AA pass for normal text)
}/* WCAG-safe color pairs — tested contrast ratios */
/* 12.63:1 — passes AAA normal text */
.high-contrast {
color: #1e293b; /* slate-800 */
background: #f8fafc; /* slate-50 */
}
/* 7.07:1 — passes AAA normal text */
.dark-theme-text {
color: #e2e8f0; /* slate-200 */
background: #0f172a; /* slate-900 */
}
/* 4.57:1 — passes AA normal, fails AAA */
.accent-on-white {
color: #1d4ed8; /* blue-700 */
background: #ffffff;
}
/* 2.14:1 — fails AA for text, but passes 3:1 for large text */
.muted-heading {
color: #94a3b8; /* slate-400 */
background: #ffffff;
}