<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohamed Nadjib</title>
    <description>The latest articles on DEV Community by Mohamed Nadjib (@mohamed_nadjib_b49954b912).</description>
    <link>https://dev.to/mohamed_nadjib_b49954b912</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4218005%2F26b9fd91-7b17-4206-abc0-cc1128f4dbee.jpg</url>
      <title>DEV Community: Mohamed Nadjib</title>
      <link>https://dev.to/mohamed_nadjib_b49954b912</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mohamed_nadjib_b49954b912"/>
    <language>en</language>
    <item>
      <title>Accessible color palette for Shopify stores: contrast checked</title>
      <dc:creator>Mohamed Nadjib</dc:creator>
      <pubDate>Fri, 30 Oct 2026 22:11:12 +0000</pubDate>
      <link>https://dev.to/mohamed_nadjib_b49954b912/accessible-color-palette-for-shopify-stores-contrast-checked-4gle</link>
      <guid>https://dev.to/mohamed_nadjib_b49954b912/accessible-color-palette-for-shopify-stores-contrast-checked-4gle</guid>
      <description>&lt;p&gt;If you build or maintain Shopify stores for European customers, you have probably seen the same worry in client emails lately: &lt;em&gt;"Is our store ready for the European Accessibility Act?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nobody can answer that with a color palette alone, and I will be clear about that below. But contrast is one of the most common, most visible and cheapest accessibility defects to fix, because you can fix it once, at the design-token level, and every page inherits the fix.&lt;/p&gt;

&lt;p&gt;So I built a small free kit: &lt;strong&gt;two accessible color palettes (light and dark) where every pair is already measured&lt;/strong&gt;, delivered as JSON tokens, CSS variables, a Tailwind config and a self-test page. In this post you get the palette, the setup for Shopify, and the 20-line script to verify any palette yourself, mine included.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the rules actually ask for
&lt;/h2&gt;

&lt;p&gt;For colors, the rules most teams care about come from WCAG 2.x, Level AA:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Text&lt;/strong&gt; needs a contrast ratio of at least &lt;strong&gt;4.5:1&lt;/strong&gt; against its background. Large text (24px regular, or about 18.66px bold) needs at least &lt;strong&gt;3:1&lt;/strong&gt;. See &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html" rel="noopener noreferrer"&gt;WCAG 1.4.3, Contrast (Minimum)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI components and graphics&lt;/strong&gt; (input borders, focus rings, icons that carry meaning) need at least &lt;strong&gt;3:1&lt;/strong&gt; against adjacent colors. See &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html" rel="noopener noreferrer"&gt;WCAG 1.4.11, Non-text Contrast&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why does this matter for EU stores? The &lt;a href="https://eur-lex.europa.eu/eli/dir/2019/882/oj" rel="noopener noreferrer"&gt;European Accessibility Act&lt;/a&gt; (Directive (EU) 2019/882) has applied since 28 June 2025 to a range of consumer-facing products and services, including e-commerce services. The technical reference most often used for websites is the harmonised standard EN 301 549, which points to WCAG 2.1 Level AA for web content. National rules and exemptions (for example for very small businesses) vary by country, so check your own situation with a qualified professional. &lt;strong&gt;This is not legal advice.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The five contrast mistakes I see most in store themes
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Placeholder text that is too light.&lt;/strong&gt; A pale gray placeholder on white often fails 4.5:1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Light gray input borders.&lt;/strong&gt; The border is what tells a user "this is a field", so it needs 3:1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Removed or invisible focus outlines.&lt;/strong&gt; &lt;code&gt;outline: none&lt;/code&gt; with no replacement leaves keyboard users lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brand-color buttons that were never checked in their hover state.&lt;/strong&gt; The default passes, the hover does not (or the reverse).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error and sale colors on tinted backgrounds.&lt;/strong&gt; Red on a pale pink badge looks fine on your monitor and fails the math.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Disabled controls are exempt from the contrast requirements, which is why you will see greyed-out buttons that do not count.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix at the token level
&lt;/h2&gt;

&lt;p&gt;Instead of patching colors page by page, define every role once, as a pair that has been measured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Minimalist Fashion, light */&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-palette&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"fashion"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#FAF8F5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-surface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#F0ECE6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#1A1816&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c"&gt;/* 16.70:1 on bg   */&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-muted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#5A534B&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c"&gt;/*  7.14:1 on bg   */&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#1A1816&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-on-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#FAF8F5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c"&gt;/* 16.70:1 on primary */&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#8A2D1C&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c"&gt;/*  8.01:1 on bg   */&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-border-strong&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#8A8379&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/*  3.53:1 on bg   */&lt;/span&gt;
  &lt;span class="py"&gt;--cpt-focus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;#2748C4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c"&gt;/*  7.04:1 on bg   */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details make this robust:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Every foreground is measured on both backgrounds you actually use.&lt;/strong&gt; A card (&lt;code&gt;--cpt-surface&lt;/code&gt;) sits on the page (&lt;code&gt;--cpt-bg&lt;/code&gt;), so text, muted text, links and messages are checked on both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State colors are part of the pair list.&lt;/strong&gt; The button label is checked on the default &lt;em&gt;and&lt;/em&gt; the hover background.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Free palette: Contrast-Proof Tokens Lite
&lt;/h2&gt;

&lt;p&gt;The free kit contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tokens.json&lt;/code&gt;: design tokens with 80 color pairs and their ratios (20 pairs × 2 palettes × light and dark)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;variables.css&lt;/code&gt;: native CSS variables, palette switching and automatic dark mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tailwind.config.js&lt;/code&gt;: copy-paste Tailwind config (v3.4+, v4 snippet in the comments)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test_page.html&lt;/code&gt;: a self-test page that recalculates every ratio in your browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The two palettes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimalist Fashion&lt;/strong&gt;: warm paper-white and ink with a terracotta accent, for editorial, low-ornament stores.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SaaS Tools&lt;/strong&gt;: crisp white and deep slate with an indigo primary and a teal accent, for dashboards and landing pages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Download it free:&lt;/strong&gt; &lt;a href="https://payhip.com/b/6FTfQ?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=lite" rel="noopener noreferrer"&gt;https://payhip.com/b/6FTfQ?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=lite&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/mohnadjib/contrast-proof-tokens-lite" rel="noopener noreferrer"&gt;https://github.com/mohnadjib/contrast-proof-tokens-lite&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Using it in a Shopify theme (Online Store 2.0)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;In the theme code editor, upload &lt;code&gt;variables.css&lt;/code&gt; to &lt;strong&gt;Assets&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;layout/theme.liquid&lt;/code&gt;, add this inside &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'variables.css'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;asset_url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;stylesheet_tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Pick a palette on the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; tag:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&amp;lt;html lang="&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;iso_code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;" data-palette="fashion"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Map your theme's selectors to the tokens in your custom CSS. For example:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.my-primary-button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="l"&gt;--cpt-primary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="l"&gt;--cpt-on-primary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.my-primary-button&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="l"&gt;--cpt-primary-hover&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.my-input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="l"&gt;--cpt-border-strong&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="l"&gt;--cpt-bg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="l"&gt;--cpt-text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;:focus-visible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="l"&gt;--cpt-focus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;outline-offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Replace &lt;code&gt;.my-primary-button&lt;/code&gt; and &lt;code&gt;.my-input&lt;/code&gt; with your theme's real class names, and &lt;strong&gt;test on a duplicate of your live theme first&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Don't trust me: verify any palette in 20 lines
&lt;/h2&gt;

&lt;p&gt;This is the exact WCAG formula. Paste it into your browser console or a Node file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mf"&gt;0.03928&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;12.92&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.055&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1.055&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;luminance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.2126&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.7152&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.0722&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;contrast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;la&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lb&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;luminance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;luminance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;la&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;la&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;contrast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#1A1816&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#FAF8F5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 16.70&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;contrast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#8A8379&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#FAF8F5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 3.54 (the kit lists 3.53: it rounds down)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two honest notes: use the exact value when you compare to a threshold (WCAG does not allow rounding up, so 4.499 is a fail), and remember that this checks the colors you pass in, not what is really rendered over a photo or gradient.&lt;/p&gt;

&lt;h2&gt;
  
  
  What color contrast will not fix
&lt;/h2&gt;

&lt;p&gt;A verified palette removes one class of defects. It does not give your store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keyboard navigation through menus, carts and modals&lt;/li&gt;
&lt;li&gt;meaningful alt text and labels&lt;/li&gt;
&lt;li&gt;a logical heading structure&lt;/li&gt;
&lt;li&gt;accessible forms and error handling&lt;/li&gt;
&lt;li&gt;reduced-motion support in your animations&lt;/li&gt;
&lt;li&gt;accessible third-party apps and widgets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Color contrast is only one part of web accessibility.&lt;/strong&gt; This kit does not guarantee that any website conforms to WCAG, EN 301 549 or the European Accessibility Act, and it is not legal advice. Test your real pages with real tools (and, when you can, with real users).&lt;/p&gt;

&lt;h2&gt;
  
  
  Your turn
&lt;/h2&gt;

&lt;p&gt;If you build for a specific sector, tell me which one in the comments: it decides which palettes I add next. And if you find a pair that fails in your own check, tell me too. That is the whole point of putting the proof in the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; the full kit is out. It has 8 sector palettes (fashion, SaaS, jewelry, home, food, wellness, education, real estate), each in light and dark, 320 measured pairs, a palette-comparison page, a Shopify install guide and a command-line checker: &lt;a href="https://payhip.com/b/1C2PJ?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=lite_to_full" rel="noopener noreferrer"&gt;Contrast-Proof Tokens, full kit&lt;/a&gt;. The two palettes from this free kit are included with identical colors.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>shopify</category>
      <category>css</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
