{"id":22293605,"url":"https://github.com/xi/apca-introduction","last_synced_at":"2025-10-05T16:55:52.794Z","repository":{"id":44666343,"uuid":"512901311","full_name":"xi/apca-introduction","owner":"xi","description":"The missing introduction to APCA","archived":false,"fork":false,"pushed_at":"2025-08-26T04:03:37.000Z","size":2150,"stargazers_count":17,"open_issues_count":8,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-08-26T06:08:58.366Z","etag":null,"topics":["a11y","apca","color","contrast"],"latest_commit_sha":null,"homepage":"https://xi.github.io/apca-introduction/tool/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-07-11T20:35:24.000Z","updated_at":"2025-08-26T04:03:40.000Z","dependencies_parsed_at":"2024-12-03T17:30:42.302Z","dependency_job_id":"eb403ecf-8f17-4ed0-88a5-bb1a790c650b","html_url":"https://github.com/xi/apca-introduction","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/xi/apca-introduction","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xi%2Fapca-introduction","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xi%2Fapca-introduction/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xi%2Fapca-introduction/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xi%2Fapca-introduction/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xi","download_url":"https://codeload.github.com/xi/apca-introduction/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xi%2Fapca-introduction/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278486278,"owners_count":25994941,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["a11y","apca","color","contrast"],"created_at":"2024-12-03T17:29:47.485Z","updated_at":"2025-10-05T16:55:52.789Z","avatar_url":"https://github.com/xi.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# The missing introduction to APCA\n\n## What is APCA?\n\nThe [Accessible Perceptual Contrast Algorithm (APCA)](https://git.apcacontrast.com/)\nis a new algorithm to estimate the visual contrast between two colors.\nIt was developed to address some issues in earlier algorithms, especially for\ndark colors.\n\nAPCA was created by Andrew Somers (Myndex) and was at some point in the\ndiscussion for the next major version of the [W3C Accessibility Guidelines\n(WCAG)](https://www.w3.org/TR/2021/WD-wcag-3.0-20211207/).\n\nAn interactive demo is available at \u003chttps://xi.github.io/apca-introduction/tool/\u003e.\n\n## Algorithm\n\n```js\nfunction sRGBtoY(srgb) {\n  var r = Math.pow(srgb[0] / 255, 2.4);\n  var g = Math.pow(srgb[1] / 255, 2.4);\n  var b = Math.pow(srgb[2] / 255, 2.4);\n  var y = 0.2126729 * r + 0.7151522 * g + 0.0721750 * b;\n\n  if (y \u003c 0.022) {\n    y += Math.pow(0.022 - y, 1.414);\n  }\n  return y;\n}\n\nfunction contrast(fg, bg) {\n  var yfg = sRGBtoY(fg);\n  var ybg = sRGBtoY(bg);\n  var c = 1.14;\n\n  if (ybg \u003e yfg) {\n    c *= Math.pow(ybg, 0.56) - Math.pow(yfg, 0.57);\n  } else {\n    c *= Math.pow(ybg, 0.65) - Math.pow(yfg, 0.62);\n  }\n\n  if (Math.abs(c) \u003c 0.1) {\n    return 0;\n  } else if (c \u003e 0) {\n    c -= 0.027;\n  } else {\n    c += 0.027;\n  }\n\n  return c * 100;\n}\n```\n\n([Source](https://git.apcacontrast.com/documentation/README#basic-apca-math-in-latex))\n\n## Thresholds\n\nThe required contrast in APCA depends on font size and weight and is defined in\na [table](https://git.apcacontrast.com/documentation/README#font-use-lookup-tables):\n\n|      | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 |\n|------|-----|-----|-----|-----|-----|-----|-----|-----|-----|\n| 12px |   — |   — |   — |   — |   — |   — |   — |   — |   — |\n| 14px |   — |   — |   — | 100 | 100 |  90 |  75 |   — |   — |\n| 15px |   — |   — |   — | 100 |  90 |  75 |  70 |   — |   — |\n| 16px |   — |   — |   — |  90 |  75 |  70 |  60 |  60 |   — |\n| 18px |   — |   — | 100 |  75 |  70 |  60 |  55 |  55 |  55 |\n| 21px |   — |   — |  90 |  70 |  60 |  55 |  50 |  50 |  50 |\n| 24px |   — |   — |  75 |  60 |  55 |  50 |  45 |  45 |  45 |\n| 28px |   — | 100 |  70 |  55 |  50 |  45 |  43 |  43 |  43 |\n| 32px |   — |  90 |  65 |  50 |  45 |  43 |  40 |  40 |  40 |\n| 36px |   — |  75 |  60 |  45 |  43 |  40 |  38 |  38 |  38 |\n| 42px | 100 |  70 |  55 |  43 |  40 |  38 |  35 |  35 |  35 |\n| 48px |  90 |  60 |  50 |  40 |  38 |  35 |  33 |  33 |  33 |\n| 60px |  75 |  55 |  45 |  38 |  35 |  33 |  30 |  30 |  30 |\n| 72px |  60 |  50 |  40 |  35 |  33 |  30 |  30 |  30 |  30 |\n| 96px |  50 |  45 |  35 |  33 |  30 |  30 |  30 |  30 |  30 |\n\nFor body text, the thresholds are even more restrictive:\n\n|      | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 |\n|------|-----|-----|-----|-----|-----|-----|-----|-----|-----|\n| 12px |   — |   — |   — |   — |   — |   — |   — |   — |   — |\n| 14px |   — |   — |   — | 100 | 100 |  90 |  75 |   — |   — |\n| 15px |   — |   — |   — | 100 |  90 |  75 |  85 |   — |   — |\n| 16px |   — |   — |   — |  90 |  75 |  85 |  75 |   — |   — |\n| 18px |   — |   — | 100 |  75 |  85 |  75 |  70 |   — |   — |\n| 21px |   — |   — |  90 |  70 |  75 |  70 |  65 |   — |   — |\n| 24px |   — |   — |  75 |  75 |  70 |  65 |  60 |   — |   — |\n| 28px |   — |   — |  85 |  70 |  65 |  60 |  58 |   — |   — |\n| 32px |   — |   — |  80 |  65 |  60 |  58 |  55 |   — |   — |\n| 36px |   — |   — |  75 |  60 |  58 |  55 |  53 |   — |   — |\n| 42px |   — |   — |   — |   — |   — |   — |   — |   — |   — |\n\n## Comparison to WCAG 2.x\n\n- WCAG 2.x produces a ratio between 1:1 and 21:1. APCA produces a value between\n  -108 and 105.\n- Unlike WCAG 2.x, APCA reports different values when you switch foreground and\n  background.\n- The result of APCA is negative for light text on dark background. You will\n  usually work with the absolute value though.\n- WCAG 2.x defines three thresholds: 3:1, 4.5:1, and 7:1. In APCA,\n  thresholds depend on other factors such as font size and weight.\n- Compared to WCAG 2.x, APCA reports drastically lower contrast for darker\n  colors. It also reports slightly higher contrast for lighter colors.\n\nAlso see my [detailed analysis](analysis.md).\n\n## Examples\n\n[![Visual comparison of WCAG 2.x and APCA (light context)](examples/screenshot-light.png)](https://xi.github.io/apca-introduction/examples/)\n[![Visual comparison of WCAG 2.x and APCA (dark context)](examples/screenshot-dark.png)](https://xi.github.io/apca-introduction/examples/)\n\n## Status\n\nWCAG is an important standard that is a normative part of many laws all over\nthe world. If APCA will be part of WCAG 3 it will have a huge impact.\nHowever, currently both WCAG 3 and APCA are still in early development.\nNeither is officially recommended by the W3C yet. Also, any mention of APCA has\nbeen [removed](https://github.com/w3c/silver/commit/d5b364de1004d76caa7ddc42c0e48860fef3730d)\nfrom the WCAG 3 draft in 2023.\n\nEvaluating a contrast algorithm is extremly difficult because contrast\nperception varies from person to person and also depends on the lighting\nconditions. Whether APCA is actually better than WCAG 2.x is therefore hard to\ntell. I personally could not say from the examples above which one works better\nfor me. A rigorous scientific evaluation is not yet available\n([issue](https://github.com/w3c/silver/issues/574)).\n\n## Why this document\n\nThe original author has published a lot of information on APCA. So why did I\ncreate this introduction?\n\nFor one it was born out of my personal frustration with the original\ndocumentation. Some important pieces of information (e.g. the actual algorithm)\nget buried under all that text.\n\nIt also contains a lot of misleading statements. For example, it claims that\nthe WCAG 2.x algorithm is not based on human perception (which it is) and that\nit produces \"invalid results\", which the author only substantiates by anecdotal\nevidence. So I felt like there was room for a more balanced introduction.\n\nAlso, contributing upstream fixes is not an option because the author is\nhostile to a critical examination of their work. You can find ample evidence\nof their behavior in the issue tracker of this repo.\n\nIf you want to dig deeper, I recommend to start with the [original WCAG\nissue](https://github.com/w3c/wcag/issues/695) and the [documentation\nREADME](https://git.apcacontrast.com/documentation/README).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxi%2Fapca-introduction","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxi%2Fapca-introduction","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxi%2Fapca-introduction/lists"}