Building a Color Contrast Checker in the Terminal
What if I could double-check that color combinations are passing the AA and/or AAA standards without leaving my code? This bash script will allow us to quickly pass in two colors and determine if they are good to go, or need to be tweaked.

Color contrast is one of the easiest accessibility features that you can make sure works on your website. People with low vision can have a hard time reading your text if the text color doesn't have enough contrast compared to the background color behind it.
I always have my terminal open while I'm working on templates, and so I want a quick and easy way to double-check the color combos I'm using right where I already am. Let's build our own color contrast checker using the API provided (for free!) by WebAIM.
Watch the video walkthrough or continue reading below!
Getting the Colors from Input
We know that we need to compare two colors, so let's grab them right from the input:
#!/bin/bash
FOREGROUND="${1//#/}"
BACKGROUND="${2//#/}"
The syntax here: "${1//#/}"
is a way of sanitizing our input, meaning that we can put any hex code regardless of whether it has the "#" and the beginning. This is using a pattern replacement: whatever is after the first two //
is what we're looking for, then whatever is after the single /
is what it will be replacing.
For example, let's say we have a string, this
, and we want to change it to that
instead. We can use the pattern replacement like this:
$mystr="this"
echo ${mystr//is/at}
Here's a quick demo:
https://youtube.com/shorts/Jgp7Paxciec?si=gckvrPitrjQLNbO8
Make Your Script Executable for Testing
Before we continue, let's make sure we can run our script and test that everything is working. In your terminal, go to the directory where your script is. Then use the command:
chmod +x checkcontrast.sh
Now that we can run our script, let's add a quick test to our script, just below our FOREGROUND
and BACKGROUND
assignments:
echo "FG: ${FOREGROUND}"
echo "BG: ${BACKGROUND}"
Now, back to your terminal, let's try running the script. I'm going to use two different hex codes, one will have the #
and one will not:
./checkcontrast #123123 ffffff
Hit enter and you should see the following output:
FG: 123123
BG: ffffff
Now that we know the script is working and it is correctly formatting our input (removing the #
), we can comment out the echo
statements to keep things clean.
The API
We'll use the free API provided by WebAIM. We'll put the endpoint into our script in the variable API_URL
, and insert the FOREGROUND
and BACKGROUND
colors that we just got from the input.
API_URL="https://webaim.org/resources/contrastchecker/?fcolor=$FOREGROUND&bcolor=$BACKGROUND&api"
Now we can call that URL and collect the result by running a curl
command and assigning the response to a new variable:
RESULT=$(curl "$API_URL")
Now we can echo out that RESULT
echo $RESULT
...and you should see something like this if you run the script:
{"ratio":"8.59","AA":"pass","AALarge":"pass","AAA":"pass","AAALarge":"pass"}
Formatting the Output
We have successfully checked the contrast between two colors, but it's not very human-readable, so let's have our script format it so it's really easy to tell where we've passed or failed.
We're going to modify our echo $RESULT
statement to do this. First, let's get rid of any characters that we won't need: {}"
. Those three characters are for JSON syntax, but they don't provide any significance in terms of readability, so we can get rid of them to start cleaning up the output.
The tr
utility's -d
will help us quickly delete those three characters:
echo $RESULT | tr -d '{}"'
Running our script as-is will now give us this:
ratio:14.1,AA:pass,AALarge:pass,AAA:pass,AAALarge:pass
Next, we'll want to put each category of standards on its own line. We can use the sed
utility to look for any commas (,
) and replace them with a new line (\n
):
echo $RESULT | tr -d '{}"' | sed 's/,/\n/g'
Now our output looks like this:
ratio:14.1
AA:pass
AALarge:pass
AAA:pass
AAALarge:pass
Finally, we can split each of our categories into two columns, using the colon character (:
) as the place to make the split. We'll use awk
to help us do this:
echo $RESULT | tr -d '{}"' | sed 's/,/\n/g' | awk -F: '{printf "%-10s %s\n", $1, $2}'
Which will result in two columns, the first having 10 characters of width, followed by the second column:
ratio 14.1
AA pass
AALarge pass
AAA pass
AAALarge pass
Breaking Down the awk Call
We started with the -F:
flag, which tells awk to look through each of our category sets and find the colon (:
) to make the split. For example, the first line goes from this:
ratio:14.1
...to this:ratio
(group one, or $1
)14.1
(group two, or $2
)
Then we use the print formatting statement (printf
) to help us format our groups. We start by assigning our two groups to two string placeholders (we'll have to add the newline character \n
back, so we'll put that there in advance):
{printf "%s %s\n", $1, $2}
The %s
acts as a placeholder, and we tell it what it should be replaced with outside of the "..."
in the order that it should be replaced. In this case, we have two string placeholders inside the quotes, and we'll replace the first one with our group one ($1
) and the second placeholder gets replaced by our group 2 ($2
).
To make the first group feel more like a column, we'll modify its placeholder to have a max-width of 10 characters (just a little more than our longest value). We also want it to be left-aligned, so we us the hyphen (-
) in front of the character width (10
) like this:
"%-10s %s\n"
Final Touches: Color
Our script is working perfectly now, and it's giving us readable output. We can make one more change to make this a pro-level script: add color to our pass or fail values.
By adding conditional logic to our awk
statement, we can check if our second group/column has the word "pass" in it, and set the color to green, or if it has the word "fail," set it to red.
Focusing just on the awk statement, we'll add and if/else chain. Starting with if the second group contains "pass," we'll use this expression, where the tilde (~
) means "contains": if ($2 ~ /pass/)
. Then set a variable called color
to the ANSI Escape Code color for green.
We'll do the same for the word "fail" and if neither pass/fail is in the group, we set the color to an empty string.
The reset
variable will be needed to change the color back to the default color at the end of the second column, so that the color doesn't leak onto all of the characters after it.
Finally, we update our printf
statement to surround the second column with our color
, the actual content of the column $2
, and then the reset
.
... awk -F: '
{
if ($2 ~ /pass/) {
color="\x1b[32m"; # Green for pass
} else if ($2 ~ /fail/) {
color="\x1b[31m"; # Red for pass
} else {
color="";
}
reset="\x1b[0m"; # Reset color
printf "%-10s %s%s%s\n", $1, color, $2, reset;
}
'
Now our output should give us colored pass/fail values for each accessibility standard, making it really easy to determine whether our color is accessible enough.

The Final Script
#!/bin/bash
FOREGROUND="${1//#/}"
BACKGROUND="${2//#/}"
# echo "FG: ${FOREGROUND}"
# echo "BG: ${BACKGROUND}"
API_URL="https://webaim.org/resources/contrastchecker/?fcolor=$FOREGROUND&bcolor=$BACKGROUND&api"
RESULT=$(curl -s "$API_URL")
echo $RESULT | tr -d '{}"' | sed 's/,/\n/g' | awk -F: '
{
if ($2 ~ /pass/) {
color="\x1b[32m"; # Green for pass
} else if ($2 ~ /fail/) {
color="\x1b[31m"; # Red for pass
} else {
color="";
}
reset="\x1b[0m"; # Reset color
printf "%-10s %s%s%s\n", $1, color, $2, reset;
}
'