Calculate the contrast ratio between your website's text and background to make sure your site is easy to read.

Get the newsletter

If you want people to find your website useful, they need to be able to read it. The colors you choose for your text can affect the readability of your site. Unfortunately, a popular trend in web design is to use low-contrast colors when printing text, such as gray text on a white background. Maybe that looks really cool to the web designer, but it is really hard for many of us to read.

The W3C provides Web Content Accessibility Guidelines, which includes guidance to help web designers pick text and background colors that can be easily distinguished from each other. This is called the "contrast ratio." The W3C definition of the contrast ratio requires several calculations: given two colors, you first compute the relative luminance of each, then calculate the contrast ratio. The ratio will fall in the range 1 to 21 (typically written 1:1 to 21:1). The higher the contrast ratio, the more the text will stand out against the background. For example, black text on a white background is highly visible and has a contrast ratio of 21:1. And white text on a white background is unreadable at a contrast ratio of 1:1.

The W3C says body text should have a contrast ratio of at least 4.5:1 with headings at least 3:1. But that seems to be the bare minimum. The W3C also recommends at least 7:1 for body text and at least 4.5:1 for headings.

Calculating the contrast ratio can be a chore, so it's best to automate it. I've done that with this handy Bash script. In general, the script does these things:

Gets the text color and background color

Computes the relative luminance of each

Calculates the contrast ratio

Get the colors

You may know that every color on your monitor can be represented by red, green, and blue (R, G, and B). To calculate the relative luminance of a color, my script will need to know the red, green, and blue components of the color. Ideally, my script would read this information as separate R, G, and B values. Web designers might know the specific RGB code for their favorite colors, but most humans don't know RGB values for the different colors. Instead, most people reference colors by names like "red" or "gold" or "maroon."

Fortunately, the GNOME Zenity tool has a color-picker app that lets you use different methods to select a color, then returns the RGB values in a predictable format of "rgb(R,G,B)". Using Zenity makes it easy to get a color value:

My script does something similar to set the background color value as $background.

Compute the relative luminance

Once you have the foreground color in $color and the background color in $background, the next step is to compute the relative luminance for each. On its website, the W3C provides an algorithm to compute the relative luminance of a color.

Since Zenity returns color values in the format "rgb(R,G,B)," the script can easily pull apart the R, B, and G values to compute the relative luminance. AWK makes this a simple task, using the comma as the field separator (-F,) and using AWK's substr() string function to pick just the text we want from the "rgb(R,G,B)" color value:

Calculating the final relative luminance is best done using the BC calculator. BC supports the simple if-then-else needed in the calculation, which makes this part simple. But since BC cannot directly calculate exponentiation using a non-integer exponent, we need to do some extra math using the natural logarithm instead:

This uses an if-then-else statement to determine which value ($r1 or $r2) is the lighter or darker color. BC performs the resulting calculation and prints the result, which the script can store in a variable.

The final script

With the above, we can pull everything together into a final script. I use Zenity to display the final result in a text box:

Contrast ratio is $rel
Contrast ratios can range from 1 to 21 (commonly written 1:1 to 21:1).

EOF

if[${rel%.*}-ge4] ; thenecho"Ok for body text"elseecho"Not good for body text"fiif[${rel%.*}-ge3] ; thenecho"Ok for title text"elseecho"Not good for title text"fi

cat<<EOF

The W3C says this:

1.4.3 Contrast (Minimum): The visual presentation of text and images of text has a contrast ratio of at least 4.5:1, except for the following: (Level AA)

Large Text: Large-scale text and images of large-scale text have a contrast ratio of at least 3:1;

Incidental: Text or images of text that are part of an inactive user interface component, that are pure decoration, that are not visible to anyone, or that are part of a picture that contains significant other visual content, have no contrast requirement.

Logotypes: Text that is part of a logo or brand name has no minimum contrast requirement.

and:

1.4.6 Contrast (Enhanced): The visual presentation of text and images of text has a contrast ratio of at least 7:1, except for the following: (Level AAA)

Large Text: Large-scale text and images of large-scale text have a contrast ratio of at least 4.5:1;

Incidental: Text or images of text that are part of an inactive user interface component, that are pure decoration, that are not visible to anyone, or that are part of a picture that contains significant other visual content, have no contrast requirement.

Logotypes: Text that is part of a logo or brand name has no minimum contrast requirement.
EOF)| zenity --text-info--title='Relative Luminance'--width=800--height=600

At the end, I like to include reference information about the W3C recommendations as a reminder for myself.

The Zenity color picker does all the hard work of interpreting colors, which the user can select by clicking in the color wheel or by entering a value. Zenity accepts standard hex color values used on websites, like #000000 or #000 or rgb(0,0,0) (all of those are black). Here's an example calculation for black text on a white background:

Zenity also understands standard color names like cadetblue or orange or gold. Enter the color name in Zenity then hit Tab, and Zenity will convert the color name into a hex color value, as in this example calculation for black text on a gold background:

Topics

About the author

Jim Hall - Jim Hall is an open source software developer and advocate, probably best known as the founder and project coordinator for FreeDOS. Jim is also very active in the usability of open source software, as a mentor for usability testing in GNOME Outreachy, and as an occasional adjunct professor teaching a course on the Usability of Open Source Software. From 2016 to 2017, Jim served as a director on the GNOME Foundation Board of Directors. At work, Jim is Chief Information Officer in local...

3 Comments

If there would seem to be any caveat with this, one needs to also consider various display screens, their brightness setting, and ambient lighting. I think you need some experiential work to test this out with your own eyeballs.

I wish more web page designers would read this. I'm no programmer, (trying to learn C++ and Python) but I can't tell you how frustrating it is to go to a site, and have their text be so unreadable that I have to copy it and paste it into a Text Editor (gEdit) just to read it! Sometimes trying to be a "cool looking" site?...can cost you visitors and hits, because now?...no matter how much I want to read something on a site?..if its hard to read?..I just close out of it and find info on what I'm looking for elsewhere! great article!!

Footer

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat.

Opensource.com aspires to publish all content under a Creative Commons license but may not be able to do so in all cases. You are responsible for ensuring that you have the necessary permission to reuse any work on this site. Red Hat and the Shadowman logo are trademarks of Red Hat, Inc., registered in the United States and other countries.