Skip to content

Commit b02d5ed

Browse files
Fix color-contrast() function for WCAG 2.1 compliance (#41585)
1 parent 64b340c commit b02d5ed

File tree

2 files changed

+140
-1
lines changed

2 files changed

+140
-1
lines changed

scss/_functions.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003
157157

158158
@each $color in $foregrounds {
159159
$contrast-ratio: contrast-ratio($background, $color);
160-
@if $contrast-ratio > $min-contrast-ratio {
160+
@if $contrast-ratio >= $min-contrast-ratio {
161161
@return $color;
162162
} @else if $contrast-ratio > $max-ratio {
163163
$max-ratio: $contrast-ratio;
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
@import "../../functions";
2+
@import "../../variables";
3+
@import "../../variables-dark";
4+
@import "../../maps";
5+
@import "../../mixins";
6+
7+
@include describe("color-contrast function") {
8+
@include it("should return a color when contrast ratio equals minimum requirement (WCAG 2.1 compliance)") {
9+
// Test case: Background color that produces contrast ratio close to 4.5:1
10+
// This tests the WCAG 2.1 requirement that contrast should be "at least 4.5:1" (>= 4.5)
11+
// rather than "strictly greater than 4.5:1" (> 4.5)
12+
13+
// #777777 produces 4.4776:1 contrast ratio with white text
14+
// Since this is below the 4.5:1 threshold, it should return the highest available contrast color
15+
$test-background: #777;
16+
$result: color-contrast($test-background);
17+
18+
@include assert-equal($result, $black, "Should return black (highest available contrast) for background with 4.4776:1 contrast ratio (below threshold)");
19+
}
20+
21+
@include it("should return a color when contrast ratio is above minimum requirement") {
22+
// Test case: Background color that produces contrast ratio above 4.5:1
23+
// #767676 produces 4.5415:1 contrast ratio with white text
24+
$test-background: #767676;
25+
$result: color-contrast($test-background);
26+
27+
@include assert-equal($result, $white, "Should return white for background with 4.5415:1 contrast ratio (above threshold)");
28+
}
29+
30+
@include it("should return a color when contrast ratio is below minimum requirement") {
31+
// Test case: Background color that produces contrast ratio below 4.5:1
32+
// #787878 produces 4.4155:1 contrast ratio with white text
33+
$test-background: #787878;
34+
$result: color-contrast($test-background);
35+
36+
// Should return the color with the highest available contrast ratio
37+
@include assert-equal($result, $black, "Should return black (highest available contrast) for background with 4.4155:1 contrast ratio (below threshold)");
38+
}
39+
40+
@include it("should handle edge case with very light background") {
41+
// Test case: Very light background that should return dark text
42+
$test-background: #f8f9fa; // Very light gray
43+
$result: color-contrast($test-background);
44+
45+
@include assert-equal($result, $color-contrast-dark, "Should return dark text for very light background");
46+
}
47+
48+
@include it("should handle edge case with very dark background") {
49+
// Test case: Very dark background that should return light text
50+
$test-background: #212529; // Very dark gray
51+
$result: color-contrast($test-background);
52+
53+
@include assert-equal($result, $color-contrast-light, "Should return light text for very dark background");
54+
}
55+
56+
@include it("should work with custom minimum contrast ratio") {
57+
// Test case: Using a custom minimum contrast ratio
58+
$test-background: #666;
59+
$result: color-contrast($test-background, $color-contrast-dark, $color-contrast-light, 3);
60+
61+
@include assert-equal($result, $white, "Should return white when using custom minimum contrast ratio of 3.0");
62+
}
63+
64+
@include it("should test contrast ratio calculation accuracy") {
65+
// Test case: Verify that contrast-ratio function works correctly
66+
$background: #767676;
67+
$foreground: $white;
68+
$ratio: contrast-ratio($background, $foreground);
69+
// Bootstrap's implementation calculates this as ~4.5415, not exactly 4.5, due to its luminance math.
70+
// We use 4.54 as the threshold for this test to match the actual implementation.
71+
@include assert-true($ratio >= 4.54 and $ratio <= 4.55, "Contrast ratio should be approximately 4.54:1 (Bootstrap's math)");
72+
}
73+
74+
@include it("should test luminance calculation") {
75+
// Test case: Verify luminance function works correctly
76+
$white-luminance: luminance($white);
77+
$black-luminance: luminance($black);
78+
79+
@include assert-equal($white-luminance, 1, "White should have luminance of 1");
80+
@include assert-equal($black-luminance, 0, "Black should have luminance of 0");
81+
}
82+
83+
@include it("should handle rgba colors correctly") {
84+
// Test case: Test with rgba colors
85+
$test-background: rgba(118, 118, 118, 1); // Same as #767676
86+
$result: color-contrast($test-background);
87+
88+
@include assert-equal($result, $white, "Should handle rgba colors correctly");
89+
}
90+
91+
@include it("should test the WCAG 2.1 boundary condition with color below threshold") {
92+
// Test case: Background color that produces contrast ratio below 4.5:1
93+
// #787878 produces 4.4155:1 contrast ratio with white
94+
$test-background: #787878; // Produces 4.4155:1 contrast ratio
95+
$contrast-ratio: contrast-ratio($test-background, $white);
96+
97+
// Verify the contrast ratio is below 4.5:1
98+
@include assert-true($contrast-ratio < 4.5, "Contrast ratio should be below 4.5:1 threshold");
99+
100+
// The color-contrast function should return the color with highest available contrast
101+
$result: color-contrast($test-background);
102+
@include assert-equal($result, $black, "color-contrast should return black (highest available contrast) for below-threshold ratio");
103+
}
104+
105+
@include it("should test the WCAG 2.1 boundary condition with color at threshold") {
106+
// Test case: Background color that produces contrast ratio close to 4.5:1
107+
// #777777 produces 4.4776:1 contrast ratio with white
108+
$test-background: #777; // Produces 4.4776:1 contrast ratio
109+
$contrast-ratio: contrast-ratio($test-background, $white);
110+
111+
// Verify the contrast ratio is below 4.5:1 threshold
112+
@include assert-true($contrast-ratio < 4.5, "Contrast ratio is below threshold, function should handle gracefully");
113+
}
114+
115+
@include it("should demonstrate the difference between > and >= operators") {
116+
// Test case: Demonstrates the difference between > and >= operators
117+
// Uses #767676 with a custom minimum contrast ratio that matches its actual ratio (4.5415)
118+
// With > 4.5415: should return black (fallback to highest available)
119+
// With >= 4.5415: should return white (meets threshold)
120+
121+
$test-background: #767676; // Produces 4.5415:1 contrast ratio
122+
$actual-ratio: contrast-ratio($test-background, $white);
123+
124+
// Test with a custom minimum that matches the actual ratio
125+
$result: color-contrast($test-background, $color-contrast-dark, $color-contrast-light, $actual-ratio);
126+
127+
// Should return white when using >= implementation
128+
@include assert-equal($result, $white, "color-contrast should return white when using exact ratio as threshold (>= implementation)");
129+
}
130+
131+
@include it("should test additional working colors above threshold") {
132+
// Test case: Background color that produces contrast ratio well above 4.5:1
133+
// #757575 produces 4.6047:1 contrast ratio with white text
134+
$test-background: #757575; // Produces 4.6047:1 contrast ratio
135+
$result: color-contrast($test-background);
136+
137+
@include assert-equal($result, $white, "Should return white for background with 4.6047:1 contrast ratio (well above threshold)");
138+
}
139+
}

0 commit comments

Comments
 (0)