Skip to content

Contrast

ColorAide provides a number of utilities related to luminance and contrast.

Relative Luminance

In the CIE XYZ and xyY color spaces, the Y parameter is linear to changes in the volume of light. Specifically this refers to the amount of reflected light where 1.0 is assumed to be a perfect reflector in relation to the reference white.

The luminance method exposes access to this value to make it quick and easy to query the relative luminance.

>>> Color("black").luminance()
0.0
>>> Color("white").luminance()
0.9999999999999999
>>> Color("blue").luminance()
0.07219231536073371

It should be noted that this luminance is relative to the XYZ D65 color space by default as this is how it is defined in the WCAG 2.1. What this means is that luminance is equivalent to the Y value of XYZ D65. We follow this convention as many people expect it in this format.

Luminance and WCAG 2.1

Luminance as described in the WCAG 2.1 spec is essentially the exact same as what the luminance method returns. The only difference is the lower precision by which they calculate the value:

>>> r, g, b = Color('purple')[:-1]
>>> r = r / 12.92 if r <= 0.03928 else ((r + 0.055) / 1.055) ** 2.4
>>> g = g / 12.92 if g <= 0.03928 else ((g + 0.055) / 1.055) ** 2.4
>>> b = b / 12.92 if b <= 0.03928 else ((b + 0.055) / 1.055) ** 2.4
>>> l = (0.2126 * r + 0.7152 * g + 0.0722 * b)
>>> print(l)
0.06147707043243851
>>> Color('purple').convert('xyz-d65')['y']
0.06148383144929487

If you'd like to have luminance in relation to a given color's white point, you can set white to None. If you'd like to get the luminance relative to some other white point, you can specify the white point as xy chromaticity points.

>>> from coloraide import cat
>>> Color('prophoto-rgb', [1, 0, 0]).luminance()
0.26831828062163154
>>> Color('prophoto-rgb', [1, 0, 0]).luminance(white=None)
0.2880711282292934
>>> Color('prophoto-rgb', [1, 0, 0]).luminance(white=cat.WHITES['2deg']['E'])
0.2905597743108222

New 2.4

The white parameter is new in 2.4.

Contrast

Chromatic contrast refers to the ability to see the difference of a colored object against a colored background. This can be very important when it comes to visual design and other fields. Determining contrast has been explored in many different ways and, depending on the application, there may be approaches to contrast that are more favorable. In the context of the web, contrast often refers to the ability to see text on a colored background and is of particular importance to those that suffer from visual impairments or disabilities.

It should be noted that as we talk about contrast, we will refer to the colors as the text and background as this is often the context in which such a function is used. As far as ColorAide is concerned, the text is always the calling color and the background is the input parameter. It is important to note this as not all contrast algorithms are symmetrical, and can differ depending which color is referenced as text, and which is referenced as the background.

At this time, ColorAide only offers a handful of contrast approaches, and they can be by using the contrast() method.

>>> Color("blue").contrast("red")
2.149390533243867

To select different contrast methods, simply use the method parameter.

>>> Color("blue").contrast("red", method='wcag21')
2.149390533243867
Methods Symmetrical Description
wcag21 WCAG 2.1 contrast ratio.
lstar Color difference between two tones in the HCT color space.

WCAG 2.1 Contrast Ratio

The WCAG 2.1 contrast ratio is registered in Color by default

ColorAide implements the color contrast ratio as outlined in the WCAG 2.1 spec. This is currently, the default contrast method. It is not without fault, but is currently the standard outlined for the web.

The contrast ratio as outlined in the WCAG 2.1 specification is simply the ratio of color luminance from a foreground and background color and is very easy to determine if you are able to acquire the luminance of the two colors.

# Where `l1` is the lighter luminance and `l2` the darker
contrast_ratio = (l1 + 0.05) / (l2 + 0.05)

This method can be used by specifying wcag21 as the contrast method.

>>> Color("blue").contrast("red", method='wcag21')
2.149390533243867

Lstar Lightness Difference

The Lstar contrast method is not registered in Color by default

Google's Material Design uses a new color space called HCT. It uses the hue and chroma from CAM16 and the tone/lightness from CIELab. For contrast, they determined using tones that are "far enough apart" in the HCT color space was a good indication of sufficient contrast. Since HCT tone is exactly the same as CIELab's lightness (also known as L*), we've referred to this approach as Lstar.

Lstar's color difference approach to contrast is quite simple, it's literally the difference between two color's lightness as provided by CIELab. This method does not care which color is text or background.

>>> Color('hct', [30, 20, 70]).contrast(Color('hct', [30, 20, 50]), method='lstar')
19.99999999995792

In order to use this contrast method, the plugin must be registered. This assumes the CIELab color space is currently registered, which it is by default.

from coloraide import Color as Base
from coloraide.contrast.lstar import LstarContrast

class Color(Base): ...

Color.register(LstarContrast())