Use WCAG contrast when the requirement is a WCAG 2.x text ratio. Measure the exact foreground and background that will be rendered, then select the threshold from the actual text size and conformance level.
Calculate a WCAG contrast ratio
ColorContrast::calculate() accepts two colors and returns their WCAG 2.x contrast ratio:
use PhpColor\Color\Color;
use PhpColor\Color\Contrast\ColorContrast;
$foreground = Color::parse('#111827');
$background = Color::parse('#ffffff');
$ratio = ColorContrast::calculate($foreground, $background);
use PhpColor\Color\Color;
use PhpColor\Color\Contrast\ColorContrast;
$foreground = Color::parse('#111827');
$background = Color::parse('#ffffff');
$ratio = ColorContrast::calculate($foreground, $background);
The result is between 1.0 for identical relative luminance and 21.0 for black and white. The calculation converts both inputs to sRGB and is symmetric, so argument order does not change the ratio.
The Color facade accepts strings when you only need the ratio:
use PhpColor\Color\Color;
$ratio = Color::contrast('#111827', '#ffffff');
use PhpColor\Color\Color;
$ratio = Color::contrast('#111827', '#ffffff');
Test WCAG AA and AAA thresholds
Use meetsFor() to calculate the ratio and test a WCAG threshold in one call:
use PhpColor\Color\Color;
use PhpColor\Color\Contrast\ColorContrast;
use PhpColor\Color\Contrast\WcagLevel;
$passes = ColorContrast::meetsFor(
Color::parse('#111827'),
Color::parse('#ffffff'),
WcagLevel::AA,
);
use PhpColor\Color\Color;
use PhpColor\Color\Contrast\ColorContrast;
use PhpColor\Color\Contrast\WcagLevel;
$passes = ColorContrast::meetsFor(
Color::parse('#111827'),
Color::parse('#ffffff'),
WcagLevel::AA,
);
PHPColor implements these text contrast thresholds:
| Level | Normal text | Large text |
|---|---|---|
WcagLevel::AA |
4.5 | 3.0 |
WcagLevel::AAA |
7.0 | 4.5 |
Set the fourth argument to true only after your application has determined that the rendered text meets the applicable WCAG definition of large-scale text:
use PhpColor\Color\Color;
use PhpColor\Color\Contrast\ColorContrast;
use PhpColor\Color\Contrast\WcagLevel;
$foreground = Color::parse('#475569');
$background = Color::white();
$passesLargeText = ColorContrast::meetsFor(
$foreground,
$background,
WcagLevel::AA,
true,
);
use PhpColor\Color\Color;
use PhpColor\Color\Contrast\ColorContrast;
use PhpColor\Color\Contrast\WcagLevel;
$foreground = Color::parse('#475569');
$background = Color::white();
$passesLargeText = ColorContrast::meetsFor(
$foreground,
$background,
WcagLevel::AA,
true,
);
PHPColor does not inspect font size, weight, rendering, or the UI element. The largeText boolean selects a threshold; it does not classify the text.
If you already have a ratio, use ColorContrast::meets():
use PhpColor\Color\Contrast\ColorContrast;
use PhpColor\Color\Contrast\WcagLevel;
$ratio = 7.2;
$passes = ColorContrast::meets($ratio, WcagLevel::AAA);
use PhpColor\Color\Contrast\ColorContrast;
use PhpColor\Color\Contrast\WcagLevel;
$ratio = 7.2;
$passes = ColorContrast::meets($ratio, WcagLevel::AAA);
Verify the rendered pair
The ratio is a property of two opaque displayed colors. Composite translucent layers first, and repeat the check after converting or serializing a repaired color. A full-precision internal value can cross a threshold differently after hexadecimal rounding.
WCAG contrast does not evaluate font rendering, state meaning, color-vision distinguishability, or whether text qualifies as large. Keep those decisions in the application.
Continue with Find accessible foregrounds, Check contrast after compositing, or Measure WCAG contrast.