How to Make Charts Easier to Distinguish for People with Different Color Vision
Coloring each series of a chart blue, green, or red does not guarantee that everyone can tell the series apart. People have different forms of color vision, and display brightness or printing can change how colors appear. A more dependable chart uses color alongside other cues: solid or striped patterns, names displayed next to the data, and numerical values. This guide uses a two-series horizontal bar chart to show how readers can compare a graph without having to recognize its colors.
Distinguish chart series with patterns, labels, and numbers
The Web Content Accessibility Guidelines (WCAG) 2.2 include the Level A requirement “Use of Color,” which says that color must not be the only visual way to distinguish information. Imagine a legend that tells readers only “blue means in person and brown means online,” without labels alongside the bars. Readers who cannot easily distinguish those hues have to work harder to identify each series.
With bar charts, one series can use a solid fill while another uses diagonal stripes. Place explicit labels such as “In person: 30” beside each bar. For a line chart, alternative non-color cues include solid versus dashed lines and differently shaped point markers, such as circles and squares. Direct labels can also reduce the need to look repeatedly between a distant legend and the plotted data, even for readers who distinguish colors easily.
Data tables are another useful safeguard. The World Wide Web Consortium (W3C) recommends equivalent textual information for complex graphics, including charts. A properly structured table lets readers examine exact values without depending on the size, pattern, or color of a bar. The example below uses invented registration figures and repeats the same values in both the visual chart and an accessible table.
Example: compare in-person and online workshop registrations
Suppose a fictional workshop has two registration routes. In-person registrations total 30 in April, 40 in May, and 50 in June; online registrations total 45, 55, and 60 over the same months. In every month, online registrations exceed in-person registrations. The horizontal bars express that difference, while labels and the table state the exact figures independently.
Use white #FFFFFF for the chart’s surface, and very pale blue-gray #F8FAFC for each bar track. Series names and numbers use dark blue-gray #1F2937, with slate #475569 for supporting instructions. The in-person series is solid blue #1D4ED8. The online series uses a striped fill alternating brown #92400E and pale yellow #FEF3C7. The stripes give the series different textures even when colors are difficult to differentiate. A visible border around each track also helps define the plotting area.
<figure class="channel-report">
<figcaption>Monthly workshop registrations (fictional data)</figcaption>
<p>All bars use the same scale, from 0 to 60 registrations.</p>
<div class="channel-bars" aria-hidden="true">
<div class="channel-month">
<h4>April</h4>
<div class="channel-row">
<span>In person: 30</span>
<div class="channel-track">
<span class="channel-fill channel-fill--venue"
style="width:50%"></span>
</div>
</div>
<div class="channel-row">
<span>Online: 45</span>
<div class="channel-track">
<span class="channel-fill channel-fill--online"
style="width:75%"></span>
</div>
</div>
</div>
<div class="channel-month">
<h4>May</h4>
<div class="channel-row">
<span>In person: 40</span>
<div class="channel-track">
<span class="channel-fill channel-fill--venue"
style="width:66.67%"></span>
</div>
</div>
<div class="channel-row">
<span>Online: 55</span>
<div class="channel-track">
<span class="channel-fill channel-fill--online"
style="width:91.67%"></span>
</div>
</div>
</div>
<div class="channel-month">
<h4>June</h4>
<div class="channel-row">
<span>In person: 50</span>
<div class="channel-track">
<span class="channel-fill channel-fill--venue"
style="width:83.33%"></span>
</div>
</div>
<div class="channel-row">
<span>Online: 60</span>
<div class="channel-track">
<span class="channel-fill channel-fill--online"
style="width:100%"></span>
</div>
</div>
</div>
</div>
<table class="channel-table">
<caption>Monthly registration values (fictional)</caption>
<thead>
<tr><th scope="col">Month</th><th scope="col">In person</th><th scope="col">Online</th></tr>
</thead>
<tbody>
<tr><th scope="row">April</th><td>30</td><td>45</td></tr>
<tr><th scope="row">May</th><td>40</td><td>55</td></tr>
<tr><th scope="row">June</th><td>50</td><td>60</td></tr>
</tbody>
</table>
</figure>
.channel-report {
max-width: 48rem;
padding: 24px;
background-color: #FFFFFF;
color: #1F2937;
}
.channel-report figcaption { font-weight: 700; }
.channel-report p { color: #475569; }
.channel-month { margin-top: 20px; }
.channel-month h4 { margin: 0 0 8px; }
.channel-row {
display: grid;
grid-template-columns: 9rem minmax(0, 1fr);
align-items: center;
gap: 12px;
margin: 8px 0;
}
.channel-track {
height: 24px;
border: 2px solid #64748B;
background-color: #F8FAFC;
}
.channel-fill {
display: block;
box-sizing: border-box;
height: 100%;
border: 2px solid;
}
.channel-fill--venue {
background-color: #1D4ED8;
border-color: #1D4ED8;
}
.channel-fill--online {
background-color: #FEF3C7;
border-color: #92400E;
background-image: repeating-linear-gradient(
135deg,
#92400E 0 6px,
#FEF3C7 6px 12px
);
}
.channel-table {
width: 100%;
margin-top: 24px;
border-collapse: collapse;
}
.channel-table th, .channel-table td {
border: 1px solid #64748B;
padding: 8px;
text-align: left;
}
@media (max-width: 500px) {
.channel-row { grid-template-columns: 1fr; gap: 4px; }
}
In the HTML (HyperText Markup Language, the markup that describes a page’s structure), each visual bar has a written series name and count immediately beside it. The table contains the same values; its th cells and scope attributes associate the month and series headers with the numbers. The bar visualization has aria-hidden="true" because the accessible table provides the equivalent data for assistive technologies. The visible chart and table remain available for sighted readers.
All six bars use a common scale from 0 to 60 registrations. A value of 30 corresponds to 50% of the available bar width, 45 to 75%, and 60 to 100%. The other values follow the same calculation, with percentages rounded to two decimal places where needed. When updating the data, change the bar width, its direct label, and the table cell together. In CSS (Cascading Style Sheets), repeating-linear-gradient() creates the diagonal stripe pattern. A brown border remains visible even if the gradient pattern is unsupported.
Check contrast and test the chart without color
Dark blue-gray labels #1F2937 against white #FFFFFF have a contrast ratio of approximately 14.68:1. Supporting slate text #475569 against white measures about 7.58:1. Both exceed the 4.5:1 generally required for normal-sized text by WCAG 2.2. Where graph shapes themselves are necessary to understand the information, the relevant Level AA non-text contrast requirement is generally 3:1 against adjacent colors.
The blue bars #1D4ED8 against the pale tracks #F8FAFC have approximately 6.41:1 contrast. The online series’ brown outlines #92400E against the same track background reach about 6.78:1. Inside those bars, brown stripes #92400E against pale-yellow stripes #FEF3C7 measure approximately 6.37:1. The gray track border #64748B against its pale background #F8FAFC reaches about 4.55:1.
These ratios do not guarantee that every person with a different form of color vision can distinguish the chart effortlessly. Test it in grayscale: check whether the solid and striped bars remain recognizably different and whether the names and figures stay readable on a narrow screen. If you publish the graphic as an image or render a more complicated visualization, supply equivalent values or a suitable description instead of relying on the image alone. Providing non-color cues and verifying contrast are related but separate checks.
HueRoll can help you explore color candidates, see HEX (hexadecimal) color codes, and compare a selected color against white or black. It does not automatically check arbitrary foreground/background pairs or determine WCAG conformance for a finished chart. After choosing the palette, verify the real graphic and its accompanying data table.