Creating Accessible Color Contrast: A Practical Guide

By Sylvester Das
•February 12, 2026
•6 min read
Choosing the right colors for your website or application is more than just aesthetics. It's crucial for accessibility. Users with visual impairments, like color blindness or low vision, might struggle to read text if the color contrast between the text and background is too low. The contrast-color() CSS function is designed to automatically select a color that provides sufficient contrast, but browser support is still limited. This article explores how to achieve similar results using existing, widely supported CSS features and a little bit of JavaScript. We'll dive into the technical details, provide practical examples, and demonstrate how to ensure your designs are accessible to everyone.
Understanding Color Contrast and Accessibility
Before diving into the code, it's important to understand the underlying principles. The Web Content Accessibility Guidelines (WCAG) define specific contrast ratios that websites should meet to be considered accessible. These ratios are based on mathematical formulas that compare the relative luminance (brightness) of two colors.
WCAG 2.0 Level AA: Requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (18pt or 14pt bold).
WCAG 2.0 Level AAA: Requires a contrast ratio of at least 7:1 for normal text and 4.5:1 for large text.
Meeting these guidelines ensures that people with moderate visual impairments can comfortably read your content.
The Challenge: Lack of contrast-color() Support
The contrast-color() function, when fully supported, would make this process much easier. You could simply specify a background color and let the browser automatically choose a contrasting text color. However, until browser support becomes widespread, we need alternative solutions.
Solution 1: CSS Custom Properties (Variables) and JavaScript
This approach leverages CSS custom properties (also known as CSS variables) to store color values and uses JavaScript to dynamically calculate and update the text color based on the background color.
Step 1: Defining CSS Custom Properties
First, define CSS custom properties for your background and text colors. We'll also define a threshold value. This threshold determines when the text color should switch between light and dark.
:root {
--background-color: #ffffff; /* Default White */
--text-color: #000000; /* Default Black */
--luminance-threshold: 0.5; /* Adjust this value */
}
body {
background-color: var(--background-color);
color: var(--text-color);
}
Step 2: Calculating Luminance in JavaScript
Next, we need a JavaScript function to calculate the relative luminance of a color. This function will convert a hex color code to its RGB components and then apply the formula for luminance calculation.
function calculateLuminance(hexColor) {
// Remove the hash (#) if present
hexColor = hexColor.replace("#", "");
// Parse hex color components
const rHex = hexColor.substring(0, 2);
const gHex = hexColor.substring(2, 4);
const bHex = hexColor.substring(4, 6);
// Convert hex to decimal
const r = parseInt(rHex, 16) / 255;
const g = parseInt(gHex, 16) / 255;
const b = parseInt(bHex, 16) / 255;
// Apply gamma correction
const a = 0.055;
const gammaCorrectedR = r <= 0.03928 ? r / 12.92 : Math.pow((r + a) / (1 + a), 2.4);
const gammaCorrectedG = g <= 0.03928 ? g / 12.92 : Math.pow((g + a) / (1 + a), 2.4);
const gammaCorrectedB = b <= 0.03928 ? b / 12.92 : Math.pow((b + a) / (1 + a), 2.4);
// Calculate relative luminance
const luminance = 0.2126 * gammaCorrectedR + 0.7152 * gammaCorrectedG + 0.0722 * gammaCorrectedB;
return luminance;
}
Technical Deep-Dive: Luminance Calculation
The luminance calculation is based on the sRGB color space and involves gamma correction. Gamma correction accounts for the non-linear way that displays output light based on input voltage. The formula 0.2126*R + 0.7152*G + 0.0722*B is a weighted average of the red, green, and blue components, reflecting the human eye's sensitivity to different colors.
Step 3: Determining the Appropriate Text Color
Now, create a function that compares the luminance of the background color to a threshold and sets the text color accordingly.
function updateTextColor() {
const backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--background-color').trim();
const luminanceThreshold = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--luminance-threshold'));
const backgroundLuminance = calculateLuminance(backgroundColor);
const textColor = backgroundLuminance > luminanceThreshold ? '#000000' : '#ffffff';
document.documentElement.style.setProperty('--text-color', textColor);
}
Step 4: Triggering the Update
Finally, call the updateTextColor() function whenever the background color changes. You can do this using JavaScript event listeners, for example, when a user selects a new background color from a color picker.
// Example: Trigger update on page load
window.addEventListener('load', updateTextColor);
// Example: Trigger update when a color picker changes
const colorPicker = document.getElementById('color-picker'); // Assuming you have a color picker element
if (colorPicker) {
colorPicker.addEventListener('change', function() {
document.documentElement.style.setProperty('--background-color', this.value);
updateTextColor();
});
}
Complete Example
<!DOCTYPE html>
<html>
<head>
<title>Dynamic Contrast Color</title>
<style>
:root {
--background-color: #ffffff;
--text-color: #000000;
--luminance-threshold: 0.5;
}
body {
background-color: var(--background-color);
color: var(--text-color);
font-family: sans-serif;
padding: 20px;
}
</style>
</head>
<body>
<h1>Dynamic Contrast Color Example</h1>
<label for="color-picker">Choose Background Color:</label>
<input type="color" id="color-picker" value="#ffffff">
<p>This text will dynamically adjust its color based on the chosen background color to ensure sufficient contrast.</p>
<script>
function calculateLuminance(hexColor) {
hexColor = hexColor.replace("#", "");
const rHex = hexColor.substring(0, 2);
const gHex = hexColor.substring(2, 4);
const bHex = hexColor.substring(4, 6);
const r = parseInt(rHex, 16) / 255;
const g = parseInt(gHex, 16) / 255;
const b = parseInt(bHex, 16) / 255;
const a = 0.055;
const gammaCorrectedR = r <= 0.03928 ? r / 12.92 : Math.pow((r + a) / (1 + a), 2.4);
const gammaCorrectedG = g <= 0.03928 ? g / 12.92 : Math.pow((g + a) / (1 + a), 2.4);
const gammaCorrectedB = b <= 0.03928 ? b / 12.92 : Math.pow((b + a) / (1 + a), 2.4);
const luminance = 0.2126 * gammaCorrectedR + 0.7152 * gammaCorrectedG + 0.0722 * gammaCorrectedB;
return luminance;
}
function updateTextColor() {
const backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--background-color').trim();
const luminanceThreshold = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--luminance-threshold'));
const backgroundLuminance = calculateLuminance(backgroundColor);
const textColor = backgroundLuminance > luminanceThreshold ? '#000000' : '#ffffff';
document.documentElement.style.setProperty('--text-color', textColor);
}
window.addEventListener('load', updateTextColor);
const colorPicker = document.getElementById('color-picker');
if (colorPicker) {
colorPicker.addEventListener('change', function() {
document.documentElement.style.setProperty('--background-color', this.value);
updateTextColor();
});
}
</script>
</body>
</html>
Solution 2: Pre-calculated Color Palettes
For simpler cases where you have a limited number of background colors, you can pre-calculate the appropriate text colors and store them in a CSS stylesheet.
.background-light {
background-color: #f0f0f0;
color: #000000;
}
.background-dark {
background-color: #333333;
color: #ffffff;
}
.background-blue {
background-color: #007bff;
color: #ffffff;
}
This approach is less dynamic but can be more efficient if you don't need real-time color adjustments.
Practical Implications
User Experience: Ensures readability and improves the overall user experience, especially for users with visual impairments.
Accessibility Compliance: Helps meet WCAG guidelines, making your website more inclusive.
Maintainability: Using CSS custom properties makes it easier to update colors throughout your website consistently.
Conclusion
While the contrast-color() function promises a simpler future for accessible color choices, we can achieve similar results today using existing CSS features and a bit of JavaScript. By understanding the principles of color contrast and luminance calculation, you can create designs that are not only visually appealing but also accessible to everyone. Remember to test your color combinations with accessibility tools to ensure they meet the required contrast ratios.
Inspired by an article from https://css-tricks.com/approximating-contrast-color-with-other-css-features/
Advertisement
Shorten Your Links, Amplify Your Reach
Tired of long, clunky URLs? Create short, powerful, and trackable links with MiniFyn. It's fast, free, and easy to use.