API Proposal: Calculate Contrast Color for Improved Accessibility
- Dominant language
- C#
- Stars
- 4.9k
- Forks
- 1.1k
- Avg merge
- 20h 23m
- Merged PRs (30d)
- 103
Description
### Background and motivation
When designing user interfaces, it is essential to ensure text or elements displayed over a background color have sufficient contrast for readability. This is particularly relevant for accessibility compliance (e.g., WCAG). Calculating a contrasting color, such as black or white, based on the background color's luminance, is a common requirement.
Currently, .NET's `Color` struct does not provide an in-built way to compute a contrast color. This proposal adds a `ContrastColor` method directly to the Color struct, allowing developers to easily determine the optimal contrasting color (black or white) for any given color.
I currently use a version of this in my applications to help get contrasting text color for different labels/controls where a user can configure its background color (such as the status bar).
Reference: https://stackoverflow.com/questions/1855884/determine-font-color-based-on-background-color
### API Proposal
```csharp
using System.Drawing;
public static class ColorExtensions
{
///
/// Calculates a WCAG 2.2 compliant contrasting color (black or white) based on the luminance of the current color.
///
/// The base color.
/// Black for bright colors, white for dark colors.
public static Color ContrastColor(this Color color);
///
/// Determines whether the specified foreground color meets or exceeds
/// the given WCAG contrast ratio when drawn over the specified background color.
///
/// The background color to test against.
/// The foreground color to verify.
///
/// The required WCAG contrast ratio. Defaults to 4.5, which is the standard for normal text.
///
///
/// true if the contrast ratio between and
/// is greater than or equal to ; otherwise false.
///
public static bool IsCompliant(Color background, Color foreground, double requiredRatio = RequiredRatio);
}
```
### API Usage
```csharp
using System.Drawing;
// Suppose you have a background color:
var background = Color.FromArgb(255, 0, 0); // Bright red
// Get a compliant foreground color:
Color foreground = background.ContrastColor();
// Check compliance explicitly if needed:
bool isAccessible = WcagContrastColor.IsCompliant(background, foreground);
```
### Alternative Designs
**Standalone Helper Function**
Instead of an extension method, a static utility function could be added in a helper class. However, attaching the method directly to Color improves discoverability and API integration.
**Configurable Threshold**
An additional overload could allow developers to specify a custom luminance threshold, but this would add complexity without significant value for most use cases.
### Risks
**Perceived Simplicity**
While the luminance formula used is standard, it assumes consistent behavior across platforms. Deviations in rendering systems or gamma settings might lead to slight visual discrepancies.
**Edge Cases**
Fully transparent colors (Color.A = 0) are handled by returning Color.Black as a fallback, which may not align with all design requirements.
### Will this feature affect UI controls?
N/A
Contributor guide
Assessment
This issue has not been assessed yet.