Accessibility Metrics

Measuring WCAG compliance.

Score Components

ComponentWeightDescription
Contrast30%Text/background ratio
Focus25%Keyboard navigation
Labels20%Form accessibility
Structure15%Semantic HTML
ARIA10%Role/state attributes

Contrast Requirements

ElementMinimum Ratio
Normal text4.5:1
Large text (18pt+)3.0:1
UI components3.0:1
Non-text content3.0:1

Calculating Contrast

fn contrast_ratio(fg: &Color, bg: &Color) -> f32 {
    let l1 = relative_luminance(fg);
    let l2 = relative_luminance(bg);

    let lighter = l1.max(l2);
    let darker = l1.min(l2);

    (lighter + 0.05) / (darker + 0.05)
}

fn relative_luminance(c: &Color) -> f32 {
    let r = linearize(c.r);
    let g = linearize(c.g);
    let b = linearize(c.b);
    0.2126 * r + 0.7152 * g + 0.0722 * b
}

Focus Indicators

RequirementPass Criteria
Visible2px+ outline
Contrast3:1 against adjacent
PersistentDoesn't disappear

Grading

ScoreGradeStatus
90-100AExcellent
80-89BGood
70-79CAcceptable
< 70FFailing

Verified Test

#[test]
fn test_accessibility_contrast_ratio() {
    use presentar_test::A11yChecker;
    use presentar_core::Color;

    // Black on white: maximum contrast
    let result = A11yChecker::check_contrast(
        &Color::BLACK,
        &Color::WHITE,
        false  // not large text
    );

    assert!(result.passes_aa);
    assert!((result.ratio - 21.0).abs() < 0.5);

    // Gray on white: lower contrast
    let gray = Color::new(0.5, 0.5, 0.5, 1.0);
    let result2 = A11yChecker::check_contrast(
        &gray,
        &Color::WHITE,
        false
    );

    // ~4.0:1 ratio - borderline
    assert!(result2.ratio > 3.0);
}