{"id":15771,"date":"2026-11-13T08:05:00","date_gmt":"2026-11-13T07:05:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?p=15771"},"modified":"2026-10-26T13:33:23","modified_gmt":"2026-10-26T12:33:23","slug":"light-and-dark-palettes-checking-contrast-and-its-limits","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/","title":{"rendered":"Light and Dark Palettes: Checking Contrast and Its Limits"},"content":{"rendered":"<p>Light and dark designs can use the same CSS variable names with different colour values. Readability, however, depends on the foreground\/background pair actually displayed. A palette supplies possible colours; usage on the page determines which contrasts require checking.<\/p><figure class=\"lw-diagram\"><img decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/dia-15771-review-20261024.png\" width=\"1120\" height=\"580\" loading=\"lazy\" alt=\"Applicable contrast threshold, actual rendering and a calculated opaque sRGB pair\"><figcaption>Applicable contrast threshold, actual rendering and a calculated opaque sRGB pair.<\/figcaption><\/figure>\n<h2>Which threshold applies?<\/h2>\n<p>WCAG 2.2 generally requires at least 4.5:1 for normal text at level AA. Large text needs 3:1: at least 18 points or 24 CSS pixels, or 14 points bold, approximately 18.67 CSS pixels. Level AAA requires 7:1 for normal text and 4.5:1 for large text. Exceptions include logos, purely decorative text and text in inactive controls.<\/p>\n<p>Visual information required to identify controls, states or meaningful graphics also falls under non-text criterion 1.4.11. The threshold is 3:1 against adjacent colours, subject to the criterion&#8217;s exceptions. Every individual border does not necessarily need that contrast if other sufficiently distinguishable features identify the component.<\/p>\n<p>A low number therefore does not automatically establish a WCAG failure. Function, size, state and actual background come first. Conversely, a variable name such as <code>--border-soft<\/code> cannot turn a necessary boundary into decoration.<\/p>\n<h2>A reproducible example<\/h2>\n<p>For opaque foreground <code>#5e7184<\/code> on <code>#f1f5f9<\/code>, the WCAG formula gives approximately 4.595593:1. This particular pair meets AA for normal text. A two-decimal display reads 4.60:1, but the comparison still uses the unrounded value.<\/p>\n<p><code>#777777<\/code> on white gives approximately 4.478089:1 and misses 4.5:1. <code>#767676<\/code> on white reaches approximately 4.542225:1. A small colour change can cross the threshold. A target of 4.6:1 provides some margin, but cannot guarantee a pass after later background changes.<\/p>\n<p>The following Python example accepts only opaque six-digit sRGB hex colours. The linearisation breakpoint is 0.04045. The older 0.03928 value selects the same branch for integer 8-bit channels; the example uses the current definition. Alpha, gradients, the CSS cascade and other colour spaces are outside its scope.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"python\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Python<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-python\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-string\">\"\"\"WCAG 2.2 ratio for two opaque six-digit sRGB hex colours only.\"\"\"<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">import<\/span> re\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">def<\/span> <span class=\"cbb-function\">luminance<\/span>(value):\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">if<\/span> <span class=\"cbb-keyword\">not<\/span> <span class=\"cbb-function\">isinstance<\/span>(value, str) <span class=\"cbb-keyword\">or<\/span> <span class=\"cbb-keyword\">not<\/span> re.<span class=\"cbb-function\">fullmatch<\/span>(<span class=\"cbb-string\">r\"#?&#91;0-9a-fA-F&#93;{6}\"<\/span>, value):\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-keyword\">raise<\/span> <span class=\"cbb-function\">ValueError<\/span>(<span class=\"cbb-string\">\"Expected six-digit opaque sRGB hex colour\"<\/span>)\n<\/span><span class=\"cbb-line\">    value = value.<span class=\"cbb-function\">removeprefix<\/span>(<span class=\"cbb-string\">\"#\"<\/span>)\n<\/span><span class=\"cbb-line\">    channels = &#91;<span class=\"cbb-function\">int<\/span>(value&#91;i:i+<span class=\"cbb-number\">2<\/span>&#93;, <span class=\"cbb-number\">16<\/span>) \/ <span class=\"cbb-number\">255<\/span> <span class=\"cbb-keyword\">for<\/span> i <span class=\"cbb-keyword\">in<\/span> (<span class=\"cbb-number\">0<\/span>, <span class=\"cbb-number\">2<\/span>, <span class=\"cbb-number\">4<\/span>)&#93;\n<\/span><span class=\"cbb-line\">    linear = &#91;c \/ <span class=\"cbb-number\">12.92<\/span> <span class=\"cbb-keyword\">if<\/span> c &lt;= <span class=\"cbb-number\">0.04045<\/span> <span class=\"cbb-keyword\">else<\/span> ((c + <span class=\"cbb-number\">0.055<\/span>) \/ <span class=\"cbb-number\">1.055<\/span>) ** <span class=\"cbb-number\">2.4<\/span>\n<\/span><span class=\"cbb-line\">              <span class=\"cbb-keyword\">for<\/span> c <span class=\"cbb-keyword\">in<\/span> channels&#93;\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-function\">sum<\/span>(w * c <span class=\"cbb-keyword\">for<\/span> w, c <span class=\"cbb-keyword\">in<\/span> <span class=\"cbb-function\">zip<\/span>((<span class=\"cbb-number\">0.2126<\/span>, <span class=\"cbb-number\">0.7152<\/span>, <span class=\"cbb-number\">0.0722<\/span>), linear))\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">def<\/span> <span class=\"cbb-function\">contrast<\/span>(foreground, background):\n<\/span><span class=\"cbb-line\">    a, b = <span class=\"cbb-function\">luminance<\/span>(foreground), <span class=\"cbb-function\">luminance<\/span>(background)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-keyword\">return<\/span> (<span class=\"cbb-function\">max<\/span>(a, b) + <span class=\"cbb-number\">0.05<\/span>) \/ (<span class=\"cbb-function\">min<\/span>(a, b) + <span class=\"cbb-number\">0.05<\/span>)\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">if<\/span> __name__ == <span class=\"cbb-string\">\"__main__\"<\/span>:\n<\/span><span class=\"cbb-line\">    ratio = <span class=\"cbb-function\">contrast<\/span>(<span class=\"cbb-string\">\"#5e7184\"<\/span>, <span class=\"cbb-string\">\"#f1f5f9\"<\/span>)\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-function\">print<\/span>(<span class=\"cbb-string\">f\"{ratio:.4f}:1; AA normal text: {ratio &gt;= 4.5}\"<\/span>)<\/span><\/code><\/pre><\/figure>\n<h2>Four limits of palette-only checking<\/h2>\n<ol><li><strong>Names do not replace usage.<\/strong> <code>--on-accent<\/code> suggests text on an accent surface, but CSS can use that value elsewhere. A value named soft can also provide important text.<\/li><li><strong>A missing override does not automatically trigger a fallback.<\/strong> A dark theme can inherit values from a shared base. Selectors, cascade and inheritance determine the computed value. A <code>var()<\/code> fallback applies under specific conditions; absence of a second declaration alone does not establish a defect.<\/li><li><strong>Transparency and gradients need the actual background.<\/strong> Alpha specifies transparency. The visible colour is calculated by combining the partly transparent colour with the layers beneath it. Images or gradients require checking the least favourable relevant area behind the text. That area can be inside a gradient, not just at an endpoint.<\/li><li><strong>States change the pairs.<\/strong> Focus, hover, selection, error messages and raised cards can introduce different backgrounds. A correct default pair does not approve every state or the entire website.<\/li><\/ol>\n\n\n<!-- lw-flux-illu 15771-a3 -->\n<figure class=\"lw-illu\"><img src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/illustrationen\/flux-15771-a3.webp\" width=\"1120\" height=\"630\" loading=\"lazy\" decoding=\"async\" alt=\"Two identical glass suncatchers hang in a window, one in front of a curtain, one in front of a wall, and look quite different. Likewise, the visible shade of a see-through area depends on what really lies beneath it.\"><figcaption>Two identical glass suncatchers hang in a window, one in front of a curtain, one in front of a wall, and look quite different. Likewise, the visible shade of a see-through area depends on what really lies beneath it.<\/figcaption><\/figure>\n\n\n<h2>Focus and form labels<\/h2>\n<p>A focus indicator marks the control currently selected for keyboard input, for example with a visible outline. An author-designed focus indicator must meet the applicable requirements for distinguishable states. WCAG 2.4.13 at level AAA adds indicator-area requirements and at least 3:1 between the same pixels in focused and unfocused states. This differs from adjacent-colour checking under 1.4.11. Unmodified browser styling and other explicitly listed cases have specific exceptions.<\/p>\n<p>Placeholder text in an active field needs the applicable text contrast. A readable placeholder still does not replace an appropriate label because the hint disappears during input. Purpose and examples should remain understandable while editing.<\/p>\n<h2>What the tool can establish<\/h2>\n<p><a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/colour-contrast-palette-auditor\/\">The linked palette auditor<\/a> calculates colour pairs locally in the browser. The current implementation extracts declarations with a text pattern and guesses roles from names. It does not resolve the real CSS cascade: the first occurrence wins when a name is repeated, and declarations inside comments can also be read. Values containing <code>var()<\/code> or <code>oklch()<\/code> are not resolved.<\/p>\n<p>Alpha values are flagged but excluded from the contrast calculation. An isolated test with completely transparent black on white therefore reports 21:1 and a good overall verdict despite an alpha warning. Another test treats <code>--text-soft<\/code> as decoration and excludes that value from findings. A good result is consequently only a clue about recognised hypothetical pairs, not acceptance testing of the rendered interface.<\/p>\n<p>Six isolated tests of the tool logic and twelve tests of the Python example support these specific statements. The calculations do not replace visual and state checks in a browser. A defensible review covers both themes, actual colour combinations and relevant control states.<\/p>\n<div class=\"lw-faq\"><h2>Questions and answers<\/h2><h3>Can a displayed ratio of 4.50 still fail?<\/h3><p>Yes. A value just below 4.5 can round to 4.50. The decision must precede rounding.<\/p><h3>Is a faint border always decoration?<\/h3><p>No. Function matters, not colour or variable name. Information needed for operation or understanding requires the applicable checks.<\/p><h3>Do two complete palettes prove accessibility?<\/h3><p>No. Palette completeness and contrast calculations cover only part of the requirements. Actual rendering, states, labels and other WCAG criteria still need separate assessment.<\/p><\/div>\n<div class=\"lw-quellen\"><h2>Sources<\/h2><ul><li><a href=\"https:\/\/www.w3.org\/WAI\/WCAG22\/Understanding\/contrast-minimum.html\" target=\"_blank\" rel=\"noopener noreferrer\">WCAG 2.2: Contrast (Minimum)<\/a><\/li><li><a href=\"https:\/\/www.w3.org\/WAI\/WCAG22\/Understanding\/non-text-contrast.html\" target=\"_blank\" rel=\"noopener noreferrer\">WCAG 2.2: Non-text Contrast<\/a><\/li><li><a href=\"https:\/\/www.w3.org\/TR\/WCAG22\/#dfn-relative-luminance\" target=\"_blank\" rel=\"noopener noreferrer\">WCAG 2.2: Relative luminance<\/a><\/li><li><a href=\"https:\/\/www.w3.org\/WAI\/WCAG22\/Understanding\/focus-appearance.html\" target=\"_blank\" rel=\"noopener noreferrer\">WCAG 2.2: Focus Appearance<\/a><\/li><li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/Guides\/Cascading_variables\/Using_custom_properties\" target=\"_blank\" rel=\"noopener noreferrer\">MDN: CSS custom properties<\/a><\/li><li><a href=\"https:\/\/www.w3.org\/WAI\/tutorials\/forms\/labels\/\" target=\"_blank\" rel=\"noopener noreferrer\">W3C WAI: Form labels<\/a><\/li><\/ul><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Contrast depends on actual colour pairs, CSS inheritance and component states. A tested sRGB example explains WCAG thresholds and rounding; concrete tool tests reveal the limits of palette-only checks.<\/p>\n","protected":false},"author":1,"featured_media":32485,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[158],"tags":[91219,92757],"class_list":["post-15771","post","type-post","status-publish","format-standard","hentry","category-tutorials-en-web-development","tag-tutorial","tag-web-development"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Light and Dark Palettes: Checking Contrast and Its Limits | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"WCAG 2.2 contrast across a light and a dark palette: five text colours below the line, how they were fixed, and four false findings a naive audit yields.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Light and Dark Palettes: Checking Contrast and Its Limits | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"WCAG 2.2 contrast across a light and a dark palette: five text colours below the line, how they were fixed, and four false findings a naive audit yields.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-11-13T07:05:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-15771-15771.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"Light and Dark Palettes: Checking Contrast and Its Limits\",\"datePublished\":\"2026-11-13T07:05:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/\"},\"wordCount\":857,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/flux-voll2-15771-15771.png\",\"keywords\":[\"Tutorial\",\"Web Development\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/\",\"name\":\"Light and Dark Palettes: Checking Contrast and Its Limits | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/flux-voll2-15771-15771.png\",\"datePublished\":\"2026-11-13T07:05:00+00:00\",\"description\":\"WCAG 2.2 contrast across a light and a dark palette: five text colours below the line, how they were fixed, and four false findings a naive audit yields.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/flux-voll2-15771-15771.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/flux-voll2-15771-15771.png\",\"width\":1200,\"height\":630,\"caption\":\"Light and Dark Palettes: Checking Contrast and Its Limits\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/light-and-dark-palettes-checking-contrast-and-its-limits\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Light and Dark Palettes: Checking Contrast and Its Limits\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Light and Dark Palettes: Checking Contrast and Its Limits | Lukas Wojcik","description":"WCAG 2.2 contrast across a light and a dark palette: five text colours below the line, how they were fixed, and four false findings a naive audit yields.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/","og_locale":"en_US","og_type":"article","og_title":"Light and Dark Palettes: Checking Contrast and Its Limits | Lukas Wojcik","og_description":"WCAG 2.2 contrast across a light and a dark palette: five text colours below the line, how they were fixed, and four false findings a naive audit yields.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-11-13T07:05:00+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-15771-15771.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"Light and Dark Palettes: Checking Contrast and Its Limits","datePublished":"2026-11-13T07:05:00+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/"},"wordCount":857,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-15771-15771.png","keywords":["Tutorial","Web Development"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/","name":"Light and Dark Palettes: Checking Contrast and Its Limits | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-15771-15771.png","datePublished":"2026-11-13T07:05:00+00:00","description":"WCAG 2.2 contrast across a light and a dark palette: five text colours below the line, how they were fixed, and four false findings a naive audit yields.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-15771-15771.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-15771-15771.png","width":1200,"height":630,"caption":"Light and Dark Palettes: Checking Contrast and Its Limits"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/light-and-dark-palettes-checking-contrast-and-its-limits\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Light and Dark Palettes: Checking Contrast and Its Limits"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/15771","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=15771"}],"version-history":[{"count":7,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/15771\/revisions"}],"predecessor-version":[{"id":33081,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/15771\/revisions\/33081"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/32485"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=15771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=15771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=15771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}