[{"data":1,"prerenderedAt":821},["ShallowReactive",2],{"guide-converting-colors-accessibility":3},{"id":4,"title":5,"body":6,"date":813,"description":814,"extension":815,"meta":816,"navigation":324,"path":817,"readingTime":315,"seo":818,"stem":819,"__hash__":820},"guides\u002Fguides\u002Fconverting-colors-accessibility.md","Converting Colors for Accessibility: Contrast Ratios and WCAG Compliance",{"type":7,"value":8,"toc":802},"minimark",[9,13,18,21,78,81,87,91,94,105,108,413,416,420,423,428,431,488,493,496,511,516,519,538,542,545,603,606,665,669,672,694,697,701,704,734,737,741,761,765,786,790,798],[10,11,12],"p",{},"Color accessibility is not about avoiding certain colors — it is about ensuring enough contrast between text and background so that everyone can read your content. WCAG 2.1 defines specific contrast ratio thresholds, and converting between color formats is often necessary to calculate and fix compliance issues.",[14,15,17],"h2",{"id":16},"contrast-ratio-requirements","Contrast Ratio Requirements",[10,19,20],{},"WCAG 2.1 defines two levels of contrast compliance:",[22,23,24,43],"table",{},[25,26,27],"thead",{},[28,29,30,34,37,40],"tr",{},[31,32,33],"th",{},"Level",[31,35,36],{},"Normal Text (\u003C 18px)",[31,38,39],{},"Large Text (≥ 18px or 14px bold)",[31,41,42],{},"UI Components & Graphics",[44,45,46,63],"tbody",{},[28,47,48,55,58,61],{},[49,50,51],"td",{},[52,53,54],"strong",{},"AA",[49,56,57],{},"4.5:1",[49,59,60],{},"3:1",[49,62,60],{},[28,64,65,70,73,75],{},[49,66,67],{},[52,68,69],{},"AAA",[49,71,72],{},"7:1",[49,74,57],{},[49,76,77],{},"—",[10,79,80],{},"These ratios compare the relative luminance of the foreground and background colors. A ratio of 4.5:1 means the lighter color is 4.5 times as luminant as the darker one.",[10,82,83,86],{},[52,84,85],{},"Common misconception",": WCAG does not ban light-gray text. It bans light-gray text on white backgrounds because the contrast falls below 4.5:1. The same gray on a dark background may pass easily.",[14,88,90],{"id":89},"calculating-contrast-ratios","Calculating Contrast Ratios",[10,92,93],{},"The contrast ratio formula requires colors in relative luminance (not hex or RGB directly):",[95,96,101],"pre",{"className":97,"code":99,"language":100},[98],"language-text","L = 0.2126 × R + 0.7152 × G + 0.0722 × B\n","text",[102,103,99],"code",{"__ignoreMap":104},"",[10,106,107],{},"Where R, G, and B are linearized (sRGB → linear) channel values between 0 and 1.",[95,109,113],{"className":110,"code":111,"language":112,"meta":104,"style":104},"language-javascript shiki shiki-themes github-light github-dark","function relativeLuminance(r, g, b) {\n  const [R, G, B] = [r, g, b].map(c => {\n    c = c \u002F 255\n    return c \u003C= 0.03928 ? c \u002F 12.92 : Math.pow((c + 0.055) \u002F 1.055, 2.4)\n  })\n  return 0.2126 * R + 0.7152 * G + 0.0722 * B\n}\n\nfunction contrastRatio(lum1, lum2) {\n  const lighter = Math.max(lum1, lum2)\n  const darker = Math.min(lum1, lum2)\n  return (lighter + 0.05) \u002F (darker + 0.05)\n}\n","javascript",[102,114,115,150,196,213,271,277,313,319,326,346,365,382,408],{"__ignoreMap":104},[116,117,120,124,128,132,136,139,142,144,147],"span",{"class":118,"line":119},"line",1,[116,121,123],{"class":122},"szBVR","function",[116,125,127],{"class":126},"sScJk"," relativeLuminance",[116,129,131],{"class":130},"sVt8B","(",[116,133,135],{"class":134},"s4XuR","r",[116,137,138],{"class":130},", ",[116,140,141],{"class":134},"g",[116,143,138],{"class":130},[116,145,146],{"class":134},"b",[116,148,149],{"class":130},") {\n",[116,151,153,156,159,163,165,168,170,173,176,179,182,185,187,190,193],{"class":118,"line":152},2,[116,154,155],{"class":122},"  const",[116,157,158],{"class":130}," [",[116,160,162],{"class":161},"sj4cs","R",[116,164,138],{"class":130},[116,166,167],{"class":161},"G",[116,169,138],{"class":130},[116,171,172],{"class":161},"B",[116,174,175],{"class":130},"] ",[116,177,178],{"class":122},"=",[116,180,181],{"class":130}," [r, g, b].",[116,183,184],{"class":126},"map",[116,186,131],{"class":130},[116,188,189],{"class":134},"c",[116,191,192],{"class":122}," =>",[116,194,195],{"class":130}," {\n",[116,197,199,202,204,207,210],{"class":118,"line":198},3,[116,200,201],{"class":130},"    c ",[116,203,178],{"class":122},[116,205,206],{"class":130}," c ",[116,208,209],{"class":122},"\u002F",[116,211,212],{"class":161}," 255\n",[116,214,216,219,221,224,227,230,232,234,237,240,243,246,249,252,255,258,260,263,265,268],{"class":118,"line":215},4,[116,217,218],{"class":122},"    return",[116,220,206],{"class":130},[116,222,223],{"class":122},"\u003C=",[116,225,226],{"class":161}," 0.03928",[116,228,229],{"class":122}," ?",[116,231,206],{"class":130},[116,233,209],{"class":122},[116,235,236],{"class":161}," 12.92",[116,238,239],{"class":122}," :",[116,241,242],{"class":130}," Math.",[116,244,245],{"class":126},"pow",[116,247,248],{"class":130},"((c ",[116,250,251],{"class":122},"+",[116,253,254],{"class":161}," 0.055",[116,256,257],{"class":130},") ",[116,259,209],{"class":122},[116,261,262],{"class":161}," 1.055",[116,264,138],{"class":130},[116,266,267],{"class":161},"2.4",[116,269,270],{"class":130},")\n",[116,272,274],{"class":118,"line":273},5,[116,275,276],{"class":130},"  })\n",[116,278,280,283,286,289,292,295,298,300,303,305,308,310],{"class":118,"line":279},6,[116,281,282],{"class":122},"  return",[116,284,285],{"class":161}," 0.2126",[116,287,288],{"class":122}," *",[116,290,291],{"class":161}," R",[116,293,294],{"class":122}," +",[116,296,297],{"class":161}," 0.7152",[116,299,288],{"class":122},[116,301,302],{"class":161}," G",[116,304,294],{"class":122},[116,306,307],{"class":161}," 0.0722",[116,309,288],{"class":122},[116,311,312],{"class":161}," B\n",[116,314,316],{"class":118,"line":315},7,[116,317,318],{"class":130},"}\n",[116,320,322],{"class":118,"line":321},8,[116,323,325],{"emptyLinePlaceholder":324},true,"\n",[116,327,329,331,334,336,339,341,344],{"class":118,"line":328},9,[116,330,123],{"class":122},[116,332,333],{"class":126}," contrastRatio",[116,335,131],{"class":130},[116,337,338],{"class":134},"lum1",[116,340,138],{"class":130},[116,342,343],{"class":134},"lum2",[116,345,149],{"class":130},[116,347,349,351,354,357,359,362],{"class":118,"line":348},10,[116,350,155],{"class":122},[116,352,353],{"class":161}," lighter",[116,355,356],{"class":122}," =",[116,358,242],{"class":130},[116,360,361],{"class":126},"max",[116,363,364],{"class":130},"(lum1, lum2)\n",[116,366,368,370,373,375,377,380],{"class":118,"line":367},11,[116,369,155],{"class":122},[116,371,372],{"class":161}," darker",[116,374,356],{"class":122},[116,376,242],{"class":130},[116,378,379],{"class":126},"min",[116,381,364],{"class":130},[116,383,385,387,390,392,395,397,399,402,404,406],{"class":118,"line":384},12,[116,386,282],{"class":122},[116,388,389],{"class":130}," (lighter ",[116,391,251],{"class":122},[116,393,394],{"class":161}," 0.05",[116,396,257],{"class":130},[116,398,209],{"class":122},[116,400,401],{"class":130}," (darker ",[116,403,251],{"class":122},[116,405,394],{"class":161},[116,407,270],{"class":130},[116,409,411],{"class":118,"line":410},13,[116,412,318],{"class":130},[10,414,415],{},"This is why converting between hex, RGB, and HSL is practical — you need numeric channel values to compute accessibility compliance.",[14,417,419],{"id":418},"fixing-common-contrast-failures","Fixing Common Contrast Failures",[10,421,422],{},"When a color combination fails WCAG, you have three options:",[10,424,425],{},[52,426,427],{},"1. Darken the text color",[10,429,430],{},"Lowering the lightness (in HSL) of the foreground is the most straightforward fix:",[95,432,436],{"className":433,"code":434,"language":435,"meta":104,"style":104},"language-css shiki shiki-themes github-light github-dark","\u002F* Fails AA: #9CA3AF on white → ratio 2.9:1 *\u002F\n.text-muted { color: #9CA3AF; }\n\n\u002F* Passes AA: #6B7280 on white → ratio 4.6:1 *\u002F\n.text-muted { color: #6B7280; }\n","css",[102,437,438,444,464,468,473],{"__ignoreMap":104},[116,439,440],{"class":118,"line":119},[116,441,443],{"class":442},"sJ8bj","\u002F* Fails AA: #9CA3AF on white → ratio 2.9:1 *\u002F\n",[116,445,446,449,452,455,458,461],{"class":118,"line":152},[116,447,448],{"class":126},".text-muted",[116,450,451],{"class":130}," { ",[116,453,454],{"class":161},"color",[116,456,457],{"class":130},": ",[116,459,460],{"class":161},"#9CA3AF",[116,462,463],{"class":130},"; }\n",[116,465,466],{"class":118,"line":198},[116,467,325],{"emptyLinePlaceholder":324},[116,469,470],{"class":118,"line":215},[116,471,472],{"class":442},"\u002F* Passes AA: #6B7280 on white → ratio 4.6:1 *\u002F\n",[116,474,475,477,479,481,483,486],{"class":118,"line":273},[116,476,448],{"class":126},[116,478,451],{"class":130},[116,480,454],{"class":161},[116,482,457],{"class":130},[116,484,485],{"class":161},"#6B7280",[116,487,463],{"class":130},[10,489,490],{},[52,491,492],{},"2. Lighten the background color",[10,494,495],{},"Sometimes the background is the problem — dark text on a dark gray background fails just as badly:",[95,497,499],{"className":433,"code":498,"language":435,"meta":104,"style":104},"\u002F* Fails AA: #111827 on #374151 → ratio 2.6:1 *\u002F\n\u002F* Passes AA: #111827 on #F3F4F6 → ratio 14.7:1 *\u002F\n",[102,500,501,506],{"__ignoreMap":104},[116,502,503],{"class":118,"line":119},[116,504,505],{"class":442},"\u002F* Fails AA: #111827 on #374151 → ratio 2.6:1 *\u002F\n",[116,507,508],{"class":118,"line":152},[116,509,510],{"class":442},"\u002F* Passes AA: #111827 on #F3F4F6 → ratio 14.7:1 *\u002F\n",[10,512,513],{},[52,514,515],{},"3. Adjust both colors",[10,517,518],{},"For accent-colored text on accent-colored backgrounds, you often need to adjust both:",[95,520,522],{"className":433,"code":521,"language":435,"meta":104,"style":104},"\u002F* Fails AA: blue-500 (#3B82F6) on blue-100 (#DBEAFE) → ratio 3.1:1 *\u002F\n\n\u002F* Passes AA: blue-700 (#1D4ED8) on blue-100 (#DBEAFE) → ratio 5.4:1 *\u002F\n",[102,523,524,529,533],{"__ignoreMap":104},[116,525,526],{"class":118,"line":119},[116,527,528],{"class":442},"\u002F* Fails AA: blue-500 (#3B82F6) on blue-100 (#DBEAFE) → ratio 3.1:1 *\u002F\n",[116,530,531],{"class":118,"line":152},[116,532,325],{"emptyLinePlaceholder":324},[116,534,535],{"class":118,"line":198},[116,536,537],{"class":442},"\u002F* Passes AA: blue-700 (#1D4ED8) on blue-100 (#DBEAFE) → ratio 5.4:1 *\u002F\n",[14,539,541],{"id":540},"dark-mode-contrast-pitfalls","Dark Mode Contrast Pitfalls",[10,543,544],{},"Dark mode introduces new contrast challenges. Colors that pass on white backgrounds may fail on dark ones:",[22,546,547,563],{},[25,548,549],{},[28,550,551,554,557,560],{},[31,552,553],{},"Combination",[31,555,556],{},"Light Mode Ratio",[31,558,559],{},"Dark Mode Ratio",[31,561,562],{},"Passes AA?",[44,564,565,578,591],{},[28,566,567,570,573,575],{},[49,568,569],{},"Gray-500 on white",[49,571,572],{},"4.6:1",[49,574,77],{},[49,576,577],{},"Yes",[28,579,580,583,585,588],{},[49,581,582],{},"Gray-500 on gray-900",[49,584,77],{},[49,586,587],{},"3.8:1",[49,589,590],{},"No",[28,592,593,596,598,601],{},[49,594,595],{},"Gray-400 on gray-900",[49,597,77],{},[49,599,600],{},"6.1:1",[49,602,577],{},[10,604,605],{},"In dark mode, muted text typically needs to be one or two shades lighter than in light mode. Use semantic color tokens with mode-specific overrides:",[95,607,609],{"className":433,"code":608,"language":435,"meta":104,"style":104},":root {\n  --color-text-muted: #6B7280; \u002F* gray-500, passes AA on white *\u002F\n}\n\n.dark {\n  --color-text-muted: #9CA3AF; \u002F* gray-400, passes AA on gray-900 *\u002F\n}\n",[102,610,611,618,633,637,641,648,661],{"__ignoreMap":104},[116,612,613,616],{"class":118,"line":119},[116,614,615],{"class":126},":root",[116,617,195],{"class":130},[116,619,620,623,625,627,630],{"class":118,"line":152},[116,621,622],{"class":134},"  --color-text-muted",[116,624,457],{"class":130},[116,626,485],{"class":161},[116,628,629],{"class":130},"; ",[116,631,632],{"class":442},"\u002F* gray-500, passes AA on white *\u002F\n",[116,634,635],{"class":118,"line":198},[116,636,318],{"class":130},[116,638,639],{"class":118,"line":215},[116,640,325],{"emptyLinePlaceholder":324},[116,642,643,646],{"class":118,"line":273},[116,644,645],{"class":126},".dark",[116,647,195],{"class":130},[116,649,650,652,654,656,658],{"class":118,"line":279},[116,651,622],{"class":134},[116,653,457],{"class":130},[116,655,460],{"class":161},[116,657,629],{"class":130},[116,659,660],{"class":442},"\u002F* gray-400, passes AA on gray-900 *\u002F\n",[116,662,663],{"class":118,"line":315},[116,664,318],{"class":130},[14,666,668],{"id":667},"apca-the-next-generation","APCA: The Next Generation",[10,670,671],{},"The Accessible Perceptual Contrast Algorithm (APCA) is proposed for WCAG 3.0. It addresses known weaknesses in the current 4.5:1 formula:",[673,674,675,682,688],"ul",{},[676,677,678,681],"li",{},[52,679,680],{},"Accommodates font size and weight"," — larger or bolder text needs less contrast",[676,683,684,687],{},[52,685,686],{},"Spatial frequency aware"," — thin lines need more contrast than large blocks",[676,689,690,693],{},[52,691,692],{},"Better for dark mode"," — the current formula overestimates contrast on dark backgrounds for small text",[10,695,696],{},"APCA is not yet required for compliance, but tools like the APCA Contrast Checker let you preview results today. Design systems built with APCA in mind will transition more easily when WCAG 3.0 arrives.",[14,698,700],{"id":699},"automated-testing","Automated Testing",[10,702,703],{},"Manually checking every color combination is impractical. Automate accessibility testing:",[673,705,706,712,718,728],{},[676,707,708,711],{},[52,709,710],{},"axe-core"," — audits contrast violations in your test suite",[676,713,714,717],{},[52,715,716],{},"Lighthouse"," — includes contrast checks in accessibility scoring",[676,719,720,723,724,727],{},[52,721,722],{},"Stylelint"," — the ",[102,725,726],{},"color-no-invalid-hex"," and custom contrast rules catch issues at lint time",[676,729,730,733],{},[52,731,732],{},"Chromatic"," — visual regression testing that flags contrast changes between PRs",[10,735,736],{},"Integrate at least one tool into your CI pipeline. Contrast failures should never reach production.",[14,738,740],{"id":739},"key-takeaways","Key Takeaways",[673,742,743,746,749,752,755,758],{},[676,744,745],{},"WCAG AA requires 4.5:1 contrast for normal text and 3:1 for large text and UI components",[676,747,748],{},"Contrast ratios depend on relative luminance — you need RGB values to calculate them",[676,750,751],{},"Fix contrast by darkening text, lightening backgrounds, or adjusting both",[676,753,754],{},"Dark mode requires separate contrast validation — light-mode-passing colors may fail",[676,756,757],{},"APCA (WCAG 3.0) will improve contrast calculation but is not yet required",[676,759,760],{},"Automate contrast testing with axe-core, Lighthouse, or Stylelint in your CI pipeline",[14,762,764],{"id":763},"related-guides","Related Guides",[673,766,767,774,780],{},[676,768,769],{},[770,771,773],"a",{"href":772},"\u002Fguides\u002Fhex-to-rgb-guide","Hex to RGB: Understanding Color Format Conversion",[676,775,776],{},[770,777,779],{"href":778},"\u002Fguides\u002Fcolor-models-explained","Color Models Explained: RGB, HSL, HEX, and More",[676,781,782],{},[770,783,785],{"href":784},"\u002Fguides\u002Fcss-custom-properties-color-values","CSS Custom Properties for Color Values",[14,787,789],{"id":788},"try-it-yourself","Try It Yourself",[10,791,792,793,797],{},"Convert colors and check contrast compliance with our free ",[770,794,796],{"href":795},"\u002Ftools\u002Fhex-to-rgb","Hex to RGB"," tool. Enter any hex value to get RGB, HSL, and other formats — then verify your color combinations meet WCAG requirements.",[799,800,801],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":104,"searchDepth":152,"depth":152,"links":803},[804,805,806,807,808,809,810,811,812],{"id":16,"depth":152,"text":17},{"id":89,"depth":152,"text":90},{"id":418,"depth":152,"text":419},{"id":540,"depth":152,"text":541},{"id":667,"depth":152,"text":668},{"id":699,"depth":152,"text":700},{"id":739,"depth":152,"text":740},{"id":763,"depth":152,"text":764},{"id":788,"depth":152,"text":789},"2026-05-28","Learn how to convert and adjust color values to meet WCAG contrast requirements — practical techniques for accessible text, UI components, and dark mode.","md",{"immutable":324},"\u002Fguides\u002Fconverting-colors-accessibility",{"title":5,"description":814},"guides\u002Fconverting-colors-accessibility","D1t7b-0mHJkxudyk6pxcVglD2a5jmFTiL5H43GJblrg",1780401332483]