Luminance and Color Contrast

Understanding Luminance, Color Contrast, and how the Rules are Changing in WCAG 3

Overview

All too often, software engineers rely on tools called color contrast checkers to check for compliance. Checkers are important, but understanding the concepts of luminance and contrast can help increase your intuition about what works and what does not. In this lesson, you learn how color contrast is calculated. You will examine the mathematical equations used in Web Content Accessibility Guidelines (WCAG) 2.2 to calculate contrast by hand. You will also learn some of the limitations of the equations in WCAG 2.2 and how WCAG 3’s new algorithm might change things.

Goals

You have the following goals for this lesson:

  • Learn the calculation for relative luminance
  • Learn the equation for contrast ratio in WCAG 2.2
  • Learn how to calculate contrast using the Accessible Perceptual Contrast Algorithm (APCA) algorithm
  • Calculate color contrast by hand to gain an intuition on how it works

Warm up

Think about how color is found and used in different technologies. Maybe there is a red error message, a blue link, a purple link, or a yellow warning. Do the different colors mean anything to you? If you removed color entirely like say removed the red from an error message consider whether you lose information. Consider the use of color in an application and its various uses.

Vocabulary

You will be learning about the following vocabulary words:

Vocabulary
TermDefinition
Relative LuminanceA numerical value often normalized between 0 (darkest black) and 1 (brightest white) used to compare the contrast of colors.
WCAG 2.2 Color ContrastA comparison of the relative luminance between two colors. The minimum and maximum range is 1 and 21 respectively.
Accessible Perceptual Contrast AlgorithmAn algorithm proposed for inclusion in WCAG 3.0 that attempts to more accurately describe contrast relative to human perception.
sRGBA Red, Green, and Blue value under the IEC 61966-2-1 [1] standard
Linear RGBAn RGB value that has been converted, typically, from sRGB or some other system, to account for human vision
Gamma CorrectionThe process of adjusting the brightness of an image to account for human vision
PolarityRefers to when dark text is on a light background, this is considered normal polarity
Reverse PolarityRefers to when light-colored text is on a dark background. It can reduce glare and be easier on the eyes in low-light conditions.

Web Content Accessibility Standards

This lesson covers the following standards:

  • WCAG 2.2 - 1.4.1 Use of Color
  • WCAG 2.2 - 1.4.3 Contrast (Minimum)
  • WCAG 2.2 - 1.4.6 Contrast (Enhanced)
  • WCAG 2.2 - 1.4.11 Non-text Contrast
  • WCAG 2.2 - 2.4.13 Focus Appearance

Explore

The concept of color sounds simple, but is often poorly understood and incredibly complex. On the surface, in computer science, color is usually thought of as three colors: red, green and blue. While this broad idea is important, when colors are combined things can get tricky. One especially important idea in color is that the WCAG standard tries to balance the idea of allowing full freedom in the design process with issues like making text easier to read.

Consider an example where you have a background color of black and a text color of black. No human, regardless of disability, would be able to read the text visually because it is the same color. By definition, this situation has the lowest possible color contrast. The hard question becomes though, what is color contrast anyway and how do you calculate it? The story of contrast inside of WCAG is not just complicated, but some might argue wrong. To even understand the debate, however, requires some math.

Past contrast, part of the reason color plays an important role in WCAG is because it is related to how information is often presented or conveyed. Color can improve aesthetics and sometimes can even improve usability, but its use requires thought. For example, it is common to attach meaning to certain colors, but when and why matters.

Because people may perceive color differently, WCAG provides guidelines about it. For example, WCAG 1.4.1 Use of Color states that color should not be the only way of visually conveying information. For example, consider if there was an error in the form if the bad input turns red, but no message is displayed. This would fail 1.4.1 because color was the only means to show the error. The fix is simple: add some words.

Although it is good to try to use other means to convey information, the reality is that color should also not be ignored. People use color for many reasons, including simple ones like making interfaces feel warm or fun. Thus, one common sense way to think about color is to use it however you see fit, so long as the text is readable and that color is not the only way information is presented. For readability, to understand what that means, you first need to grasp the concept of relative luminance.

Relative Luminance

To be able to compare colors you have to be able to describe how well a person can perceive a color. It is generally understood that the human visual system is more perceptive to brightness (luminance) than the differences in hue. Brightness in this context can be thought of as how light or dark the color is, whereas hue is sort of like its angle on a color wheel. WCAG uses relative luminance to calculate a brightness from a given color.

The following calculation will give you the relative luminance of a color (L). Note that it is not the actual physical brightness of the color in physics, but closer to how bright the human eye perceives it. The relative luminance of a color is defined in the context of a particular color standard, IEC 61966-2-1:1999 [1] and is typically called sRGB color space is calculated as follows:

L = 0.2126×R + 0.7152×G + 0.0722×B

where R, G, and B are defined as:

If RsRGB 0.03928, then R = RsRGB 12.92 ; else R = ( RsRGB + 0.055 1.055 ) 2.4 If GsRGB 0.03928, then G = GsRGB 12.92 ; else G = ( GsRGB + 0.055 1.055 ) 2.4 If BsRGB 0.03928, then B = BsRGB 12.92 ; else B = ( BsRGB + 0.055 1.055 ) 2.4

and RsRGB, GsRGB, and BsRGB are defined as:

RsRGB = R8bit 255 GsRGB = G8bit 255 BsRGB = B8bit 255

Example

To help understand, consider a tangible example with a worked example going through the following calculation of the luminance of a color. Take royal blue which in 8 bit RGB is (65, 105, 225). The first step is to normalize the colors. You do this by using the equations for the sRGB colors:

RsRGB = 65 255 0.25490 GsRGB = 105 255 0.41176 BsRGB = 225 255 0.88235

Note that results are truncated here for simplicity.

Now that you have the normalized values, you find the R, G, and B values for the luminance equation. The relative luminance equation expects the color values to be in a format that is proportional to light intensity. This is sometimes referred to as lacking gamma correction, meaning it is taking into account physics but not human perception. In computer science, the technical name for this is linear RGB, which means the above numbers must be converted. All 3 values are greater than 0.03928 so you use the equations with the exponent as follows:

R = ( 0.25490 + 0.055 1.055 ) 2.4 0.05286 G = ( 0.41176 + 0.055 1.055 ) 2.4 0.14126 B = ( 0.88235 + 0.055 1.055 ) 2.4 0.75294

Now you plug into the relative luminance equation as follows:

L = 0.2126×0.05286 + 0.7152×0.14126 + 0.0722×0.75294 L = 0.01124 + 0.10103 + 0.05436 L 0.167

So the luminance of the color royal blue is about 0.167. Looking back on the calculations, there are some things to note. First of all, of the 3 color components, the largest of the components was blue. The final value for B was 0.75293 which is larger than the next largest component (green). However, if you look at the luminance equation, each color component has a coefficient and the largest is green by far. Essentially, there is a lot of blue, but blue does not impact luminance very much. Next, consider contrast.

Contrast Ratio

While luminance tells you how bright a color is, contrast ratio tells you how different the brightness of two colors are and different versions of WCAG have different approaches. The two colors could come from a text and its background and the contrast ratio describes how well you can distinguish between both colors.

WCAG 2.2 gives the following formula for contrast ratio:

CR = L1 + 0.05 L2 + 0.05

Where L1 is the relative luminance of the lighter of the colors and L2 is the darker of the colors.

Since luminance can only range from 0 to 1 that means with this equation the maximum ratio comes out to 21:1.

Example

Now take the luminance of royal blue that you calculated earlier, which was 0.167 and calculate the contrast ratio when compared to white which has a luminance of 1.

CR = 1 + 0.05 0.167 + 0.05 = 1.05 0.217 4.84

The contrast ratio between royal blue and white would be considered to be 4.84:1.

The required ratio for normal text is 4.5:1 so this color combination would pass. For large text and graphic objects the required ratio is 3:1 so this color combination would also pass in those cases. Note that WCAG defines large text to be 18pt, or 14pt bold font or bigger to be considered large.

Note how to calculate contrast using this method the only variables were the luminance of the colors. It did not take into account which color is the background. It also largely did not take into account the size of the text, except for big or small. While WCAG 3.0 is still being drafted, there is reasonable skepticism that WCAG 2.2's approach makes sense. As such, a new approach is being considered and thinking through the mathematical differences is interesting. This is called the Accessible Perceptual Contrast Algorithm [2].

Accessible Perceptual Contrast Algorithm

The Accessible Perceptual Contrast Algorithm (APCA) is a method for calculating color contrast which puts more emphasis on readability. APCA aims to improve over the older and traditional methods of calculating contrast. Instead of producing a ratio, APCA gives a score to a color combination and then based on the font size and weight there are thresholds where the combination is considered to have a sufficient contrast.

In the APCA, contrast is calculated based on screen luminance while accounting for human perception. This begins with computing the luminance of each color involved in the contrast comparison. APCA defines two ways to calculate luminance: the exact screen luminance (Y), and an estimated screen luminance (YS) used for performance optimization.

Exact Screen Luminance (Y) is calculated similarly to the relative luminance defined in WCAG 2, but with two key differences. First, APCA uses a slightly higher linearization threshold for sRGB values, 0.04045 instead of 0.03928. Second, the weights for R, G, and B have greater precision: 0.2126729, 0.7151522, and 0.0721750, respectively, rather than the rounded 0.2126, 0.7152, and 0.0722 used in WCAG 2. These differences provide a more perceptually accurate measure of screen luminance for contrast calculations.

Y = 0.2126729 × R + 0.7151522 × G + 0.0721750 × B

where R, G, and B are now defined as:

If RsRGB 0.04045, then R = RsRGB 12.92 ; else R = ( RsRGB + 0.055 1.055 ) 2.4 If GsRGB 0.04045, then G = GsRGB 12.92 ; else G = ( GsRGB + 0.055 1.055 ) 2.4 If BsRGB 0.04045, then B = BsRGB 12.92 ; else B = ( BsRGB + 0.055 1.055 ) 2.4

and RsRGB, GsRGB, and BsRGB are the same as previously defined, under Relative Luminance.

Estimated Screen Luminance (YS) avoids full gamma correction and instead estimates luminance directly from the 8-bit sRGB values, it still includes the higher precision weights for R, G and B. While this method is computationally faster and suitable for real-time environments, it is less precise and may not capture subtle luminance differences as effectively as the full version.

YS = 0.2126729 × ( R8bit 255 ) 2.4 + 0.7151522 × ( G8bit 255 ) 2.4 + 0.0721750 × ( B8bit 255 ) 2.4

Now, this is where APCA starts to set itself apart from the Relative Luminance calculations in WCAG 2.0. APCA considered the fact that for certain colors that are near black, those dark shades of colors become indistinguishable on most displays. To take those dark shades into account after you get the screen luminance you are going to clamp those values. The constants Bthresh = 0.022 and Bexp = 1.414 are used in the clamping function for these dark shades. The threshold marks where luminance is too low for linear behavior, and the exponent adjusts contrast to better match human perception. These values are fixed in standard APCA and can be used as-is for most applications.

The clamp function for a given screen luminance (Y) is defined as:

If Y 0.022 , then Clamp ( Y ) = Y ; else Clamp ( Y ) = Y + ( 0.022 Y ) 1.414

APCA was designed to account for how humans perceive text on the screen. Relative Luminance does not account for which color is the foreground, and which was in the background. The next step here for APCA is to differentiate the text color and background color and you will be using the clamped screen luminance for those:

Ytext = Clamp ( Y )

where Y is the screen luminance derived from the color of the text or object.

Ybg = Clamp ( Y )

where Y is the screen luminance derived from the color used for the background.

Once you have the clamped screen luminance values for both the text and background colors, the next step is to determine the contrast polarity. If the background is lighter than the text, this is known as normal polarity (dark text on a light background, often called light mode). If the background is darker, it is called reverse polarity (light text on a dark background or dark mode). Polarity is determined by comparing the luminance values, whichever color has the higher luminance is considered the lighter one.

To compute the raw contrast signal (S) in APCA, a power function is applied to the clamped luminance values of the text and background. This step accounts for the non-linear way the human eye perceives brightness [3], our visual system does not interpret a 50% drop in light intensity as a 50% drop in brightness. APCA uses different exponents based on polarity to better align with this perceptual curve. If the absolute difference between the luminance values is smaller than the perceptual input threshold (Pin) of 0.0005, the contrast is considered imperceptible and treated as zero to prevent false contrast detection.

If Ybg Ytext < 0.0005 , then S = 0 else if Ybg > Ytext , then S = Ybg 0.56 Ytext 0.57 else , S = Ybg 0.65 Ytext 0.62

Up to this point you have been using the raw contrast values, but APCA found it more helpful to develop a contrast score (C) by scaling the raw signal to more easily gauge differences in contrast. The scale factor (Rscale) is simply 1.14 and the equation is as follows.

C = S × 1.14

To further reduce contrast values that are mathematically present but imperceptible to the human eye, APCA applies a small offset (0.027) to the contrast value, producing the Scaled Absolute Perceptual Contrast (Sapc). This offset, often referred to as Woffset, helps discount faint differences that do not meaningfully impact legibility. Additionally, any Sapc value below the perceptual output threshold (Pout) of 0.1 is considered too weak to be useful and is set to zero. Using these constants directly simplifies the logic while still aligning with APCA’s perceptual goals.

If |C| < 0.1 , then Sapc =0 else if C > 0 , then Sapc =C0.027 else , Sapc =C+0.027

Now the final score is calculated by multiplying the absolute perceived contrast by 100:

LC = Sapc × 100

The following information is subject to change as WCAG 3.0 is still being written, so do not take the exact values to heart. With contrast scores, instead of a hard requirement of 3:1 like WCAG 2.0, the idea is to take the score and see what thresholds the score meets based on the context, size, and weight of the text.

Note that if the color pair has a normal polarity the value will be positive, and if the polarity was reversed the score will be negative. But for the next step of testing the score for pass/fail purposes you will ignore the sign on the score and just consider the absolute value.

Here are some example thresholds to keep in mind for the final contrast score (LC):

  • LC 90 - Preferred level for fluent text and columns of body text with a font no smaller than 14px/weight 400.
  • LC 75 - The minimum level for columns of body text with a font no smaller than 18px/400. Consider LC 75 as a minimum for text where readability is important.
  • LC 60 - The minimum level recommended for content text that is not body, column, or block text. In other words, text you want people to read. The minimums: 24px normal weight (400) or 16px/700 (bold).
  • LC 45 - The minimum for larger, heavier text (36px normal weight or 24px bold) such as headlines. This is also the minimum for pictograms with fine details.
  • LC 30 - The absolute minimum for any text not listed above. This includes placeholder text and disabled element text. This is also the minimum for large/solid semantic & understandable non-text elements.
  • LC 15 - The absolute minimum for any non-text that needs to be discernible and differentiable, and is no less than 5px in its smallest dimension. This may include disabled large buttons. Designers should treat anything below this level as invisible. Less than LC 15 will not be visible for many users. Avoid less than LC 30 for anything important for the use, understanding, or interaction of the site.

With the score there are either ranges that are acceptable based on context and there are also lookup tables to use based on the font size and font weight being used. Here is an example of a lookup table:

APCA Font to Contrast Table
Font100200300400500600700800900
12pxØØØØØØØØØ
14pxØØØ100B100B90B75BØØ
15pxØØØ100B90B75B70+15ØØ
16pxØØØ90B75B70+1560+1560Ø
18pxØØ100B75B70+1560+1555+155555
21pxØØ90B70B60+1555+1550+155050
24pxØØ75B60+1555+1550+1545+154545
28pxØ10070+1555+1550+1545+1543+154343
32pxØ9065+1550+1545+1543+1540+154040
36pxØ7560+1545+1543+1540+1538+153838
42px1007055434038353535
48px906050403835333333
60px755545383533303030
72px605040353330303030
96px504535333030303030

For this table if there is B next to the score that means that value is appropriate for body text at the given score. The +15 represents a safety buffer. So if the cell is 45+15 that means the 45 is the minimum but 60 would be the preferred to account for other variations. An Ø means there is no contrast score where that pair would be distinguishable.

For APCA instead of giving a contrast requirement as a ratio the context of the text and its size and weight is factored in rather than a hard cutoff at one specific size like in WCAG. This is one of the ways that APCA aims to better represent human perception over the traditional method.

Example

Now you will walk through a real example using the same colors from earlier, royal blue text with RGB values (65, 105, 225) on a white background (255, 255, 255) which has a screen luminance of 1.0. You will compare how the contrast is calculated using the older WCAG 2.0 method versus the new WCAG 3.0 APCA method. You will see just how much more nuanced and accurate APCA is when it comes to modeling human visual perception—especially for color and brightness!

To follow the APCA exact screen luminance method, you will first convert the sRGB values to linear light using a gamma correction step based on a threshold of 0.04045. However, you can use the estimated screen luminance method if you wish. Then you will determine contrast polarity and raw contrast, apply perceptual modeling, and finally scale it into a meaningful contrast score.

Before you calculate exact screen luminance, you need to normalize and linearize the 8-bit RGB values. This accounts for gamma correction, since human vision doesn’t perceive brightness linearly.

RsRGB = 65 255 0.25490 GsRGB = 105 255 0.41176 BsRGB = 225 255 0.88235

You can see that each of the normalized sRGB values is greater than the linearization threshold of 0.04045 so R, G, and B are calculated as:

R = ( 0.25490 + 0.055 1.055 ) 2.4 0.05286 G = ( 0.41176 + 0.055 1.055 ) 2.4 0.14126 B = ( 0.88235 + 0.055 1.055 ) 2.4 0.75294

You may have noticed that up to this point in the example, the values are essentially the same as in the earlier luminance example. In fact, for this color combination, if you chose the estimated screen luminance method you would get a result of about 0.167, which is the same result as the exact method.

Y = 0.2126729×0.05286 + 0.7151522×0.14126 + 0.0721750×0.75294 Y = 0.01124 + 0.10102 + 0.05434 Y 0.167

Now you can move on to the next steps of APCA. First, you will need to clamp the dark shades. The text luminance (0.167) and the background luminance (1.0) are both above the threshold of 0.022, which means they do not require clamping. Therefore, you can now evaluate the polarity and compute the raw contrast signal for the two luminances. To do this, first check if the absolute value of the difference is above the perceptual input threshold of 0.0005. It is, so now you can check the polarity; remember if the luminance of the background is greater than the luminance of the text, it is considered normal polarity:

Because it has normal polarity, the raw contrast signal (S) is computed as:

S = 1.0 0.56 0.167 0.57 S = 1.0 0.36054 S 0.63946

Next, you will scale the raw signal to get a contrast score:

C = 0.63946 × 1.14 C 0.72898

Now, you want to reduce the values that are not perceptible to the human eye by applying the offset. First you must check that your contrast score (C) is greater than the perceptual output threshold of 0.1, then you can apply the offset according to the polarity. You will notice that for this color combination, C is positive (normal polarity) so the Sapc is computed as:

Sapc = 0.72898 - 0.027 Sapc = 0.70198

Finally, multiply your Scaled Absolute Perceptual Contrast (Sapc) by 100 to get the final contrast score:

LC = 0.70198 × 100 LC = 70.198

Citations

  1. IEC 61966-2-1 Multimedia systems and equipment - Colour measurement and management - Part 2-1: Colour management - Default RGB colour space - sRGB. International Electrotechnical Commission https://webstore.iec.ch/en/publication/6169
  2. Accessible Perceptual Contrast Algorithm SAPC-APCA. Myndex Technologies https://github.com/Myndex/SAPC-APCA
  3. Thomas Norton, David Corliss, James Bailey (2020). The Psychophysical Measurement of Visual Function. 1st edition. Butterworth-Heinemann. Pages 29-30

Engage

Now that you have seen how color contrast is calculated you will by hand find the contrast ratio between various sets of two colors.

Directions

For each of the color pairs below you will work out the contrast using Relative Luminance and get a Contrast Ratio as described by WCAG 2.2. And then you will also for that same color pair find the contrast score using the APCA method.

DO NOT PLUG THESE PAIRS INTO A COLOR CONTRAST CALCULATOR.

Doing these by hand will allow better understanding of how these equations work and how colors are evaluated. Now that does not mean all the way by hand you can still use a normal calculator for your math.

After you get a contrast ratio using the WCAG 2.2 method check if that ratio meets the requirements as set by WCAG 2.2. For the APCA contrast score check what threshold the score meets and find what the appropriate size and font weight would be for the score if there is one.

The color pairs are given as foreground first and background second:

  1. (0, 0, 0) – (255,255,255)
  2. (255,255,255) – (0,0,0)
  3. (119,119,119) – (255,255,255)
  4. (0,120, 215) – (255,255,255)
  5. (0,128,0) – (255,255,255)
  6. (255,20,147) – (255,255,255)
  7. (0,255, 255) – (0,0,0)
  8. (255, 215, 0) – (0,0, 128)
  9. (199,21,133) – (230,230,250)
  10. (0,255, 127) – (25,25,112)
  11. (255,165, 0) – (255,255,255)
  12. (127, 255, 0) – (0,0,0)
  13. (30,144,255) – (255,255,255)
  14. (50, 205, 50) – (255,250,250)
  15. (218, 112, 214)– (0,0,0)

Wrap up

This lesson explored how luminance is calculated and how that relates to contrast ratio. This lesson also goes further and explores the APCA method of calculating contrast and how that takes a different approach. Understanding how these methods work gives insight on how color affects your perception of different types of content. Getting contrast right helps make better and more accessible design choices and creates better content for as many people as possible.

Next Tutorial

In the next tutorial, we will discuss Color In Application, which describes how to use color contrast calculators in practice.