In Ancient Egypt, hieroglyphs were painted in vivid colors on contrasting backgrounds - not for decoration, but so they could be read even in dark temple chambers. Today the same principle applies in web design: content must be readable for everyone.
WCAG defines minimum contrast requirements between text and background:
| Level | Normal text | Large text (18px bold / 24px) | |:---|:---|:---| | AA | 4.5:1 | 3:1 | | AAA | 7:1 | 4.5:1 |
1/* GOOD - high contrast */
2.good-contrast {
3 color: #1a1a2e; /* Dark text */
4 background-color: #f5f1e3; /* Light background */
5 /* Contrast: ~12:1 - meets AAA */
6}
7
8/* BAD - too low contrast */
9.bad-contrast {
10 color: #999999; /* Gray text */
11 background-color: #cccccc; /* Gray background */
12 /* Contrast: ~1.8:1 - does not meet even AA */
13}
14
15/* FIXED */
16.fixed-contrast {
17 color: #595959; /* Darker gray */
18 background-color: #ffffff; /* White background */
19 /* Contrast: ~5.9:1 - meets AA */
20}Color cannot be the only way to convey information - people with color blindness may not distinguish certain colors.
1<!-- BAD - only color indicates error -->
2<style>
3 .error-field { border-color: red; }
4</style>
5<input type="email" class="error-field">
6
7<!-- GOOD - color + icon + text -->
8<style>
9 .error-field {
10 border: 2px solid #d32f2f;
11 background-image: url('error-icon.svg');
12 background-repeat: no-repeat;
13 background-position: right 8px center;
14 }
15</style>
16<input type="email" class="error-field"
17 aria-invalid="true"
18 aria-describedby="email-err">
19<p id="email-err" class="error-msg">
20 <span aria-hidden="true">❌</span>
21 Please enter a valid email address
22</p>1/* Use relative units */
2body {
3 font-size: 100%; /* = 16px by default */
4}
5
6h1 { font-size: 2rem; } /* 32px */
7h2 { font-size: 1.5rem; } /* 24px */
8p { font-size: 1rem; } /* 16px */
9small { font-size: 0.875rem; } /* 14px - minimum! */
10
11/* NEVER block text zooming */
12/* BAD */
13html { font-size: 16px !important; }
14/* GOOD */
15html { font-size: 100%; }1/* WCAG requires at minimum: */
2p {
3 line-height: 1.5; /* Line height: 1.5x font size */
4 letter-spacing: 0.12em; /* Letter spacing */
5 word-spacing: 0.16em; /* Word spacing */
6}
7
8/* Paragraph spacing >= 2x font size */
9p + p {
10 margin-top: 2em;
11}1/* Optimal line width: 50-80 characters */
2.article-content {
3 max-width: 70ch; /* 70 characters */
4 margin: 0 auto;
5}In CSS you can use
color-contrast() (experimental) or use tools:1/* Use CSS variables for consistency */
2:root {
3 --text-primary: #1a1a2e;
4 --text-secondary: #4a4a5a;
5 --bg-primary: #ffffff;
6 --bg-secondary: #f5f1e3;
7 --accent: #8b6914;
8 --error: #d32f2f;
9 --success: #2e7d32;
10}
11
12/* High contrast mode */
13@media (prefers-contrast: high) {
14 :root {
15 --text-primary: #000000;
16 --text-secondary: #1a1a1a;
17 --bg-primary: #ffffff;
18 --accent: #6b4c00;
19 }
20}
21
22/* Dark mode */
23@media (prefers-color-scheme: dark) {
24 :root {
25 --text-primary: #e0e0e0;
26 --text-secondary: #b0b0b0;
27 --bg-primary: #1a1a2e;
28 --bg-secondary: #2d2d44;
29 }
30}1/* High contrast mode */
2@media (prefers-contrast: high) {
3 button {
4 border: 3px solid currentColor;
5 }
6}
7
8/* Forced colors mode (e.g., Windows High Contrast) */
9@media (forced-colors: active) {
10 .card {
11 border: 2px solid ButtonText;
12 }
13
14 a {
15 color: LinkText;
16 }
17
18 /* Decorative backgrounds are removed - add borders */
19 .highlight {
20 forced-color-adjust: none;
21 /* OR preserve original colors */
22 }
23}Just as ancient Egyptians ensured the readability of hieroglyphs painted on temple walls, so must we ensure the readability of text on our pages - so that everyone can read our message, regardless of conditions.