{"id":330342,"date":"2020-12-10T11:34:26","date_gmt":"2020-12-10T19:34:26","guid":{"rendered":"https:\/\/css-tricks.com\/?p=330342"},"modified":"2020-12-10T11:34:28","modified_gmt":"2020-12-10T19:34:28","slug":"using-css-custom-properties-to-adjust-variable-font-weights-in-dark-mode","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/using-css-custom-properties-to-adjust-variable-font-weights-in-dark-mode\/","title":{"rendered":"Using CSS Custom Properties to Adjust Variable Font Weights in Dark Mode"},"content":{"rendered":"\n

Black isn\u2019t always slimming.<\/p>\n\n\n\n

When recently testing a dark mode option for one of my sites, I experienced first-hand the issue that Robin Rendle addresses in this article<\/a>. All of my page text \u2014 headings and body copy \u2014 appeared to bulk up when I switched to dark mode. And it didn\u2019t matter what fonts I used or which browsers I tried. The same thing happened with all of them.<\/p>\n\n\n\n\n\n\n\n

For example, here\u2019s what happens with Adobe\u2019s Source Sans Pro in Chrome for Windows:<\/p>\n\n\n\n

\"\"
See those blurry edges when we switch to dark mode?<\/figcaption><\/figure>\n\n\n\n

It\u2019s not an illusion. The light characters really are heavier against dark backgrounds. We can zoom in to see better:<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n
\"\"
The characters really are thicker in dark mode!<\/figcaption><\/figure>\n\n\n\n

And it becomes really obvious when we invert the dark mode portions of those images:<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n
\"We
We can really see the difference when putting the characters side-by-side on the same white background.<\/figcaption><\/figure>\n\n\n

One solution<\/h3>\n\n\n

Since variable fonts enjoy wide browser support, we can use them to help us address this issue. The three panels below demonstrate a solution we\u2019ll be working toward:<\/p>\n\n\n\n

\"\"
The top shows us some light text on a dark background. The middle panel shows what happens in dark mode without changing any font weight settings. And the bottom panel demonstrates dark mode text that we\u2019ve thinned out a bit. That third panel is adjusted to match the weight of its light counterpart, which is what we\u2019re trying to accomplish here.<\/figcaption><\/figure>\n\n\n\n

Here\u2019s how we can get this improved effect:<\/p>\n\n\n\n

  1. Reduce font-weight<\/code> properties in dark mode via one of the following methods:
    1. Manually changing each font-weight<\/code> assignment directly in a dark mode media query.<\/li>
    2. Creating a single --font-weight-multiplier<\/code> custom property that changes its value in dark mode, and by which we can then multiply by each element\u2019s default font-weight<\/code> value.<\/li>
    3. Same thing, but instead of calculating each element\u2019s font-weight<\/code> property individually, we take advantage of CSS variable scoping and the universal selector (*<\/code>) to apply our multiplier calculation everywhere at once.<\/li><\/ol><\/li>
    4. Adjust a variable font\u2019s grade (“GRAD”) axis. Not all variable fonts support this specific feature, but Roboto Flex<\/a>, does. Altering this axis value changes the font\u2019s apparent weight, without affecting the width of the letters.<\/li>
    5. Adjust a variable font\u2019s darkmode (\"DRKM\"<\/code>) axis. Dalton Maag\u2019s aptly-named Darkmode, with its eponymous darkmode axis, is uniquely suited for this. As with the Roboto Flex\u2019s grade axis, adjusting Darkmode\u2019s darkmode axis changes the font\u2019s apparent weight. But while the grade axis requires some fine-tuning of values, the darkmode axis is simply switched on (thinner) or off (regular).<\/li><\/ol>\n\n\n\n

      The techniques in the first group work for most variable fonts. The solution Robin uses in his article is actually the very first item in the group. I\u2019ll expand on the second and third items in the group by introducing custom properties that help us automatically adjust font weights in dark mode.<\/p>\n\n\n\n

      The second and third groups involve less common font-variation-settings<\/code> axes. Though these strategies apply to fewer typefaces, they may be preferable when available. The trick is knowing what a variable font supports before choosing it.<\/p>\n\n\n\n

      I\u2019ve made a demonstration page including all the strategies covered in this article. You can see what some different variable fonts look like in light mode, in dark mode with no adjustment, and in dark mode with our solutions for thinning out characters.<\/p>\n\n\n\n

      \n
      View Demo<\/a><\/div>\n<\/div>\n\n\n\n

      In addition to the strategies listed above, there\u2019s always one more option: don\u2019t do anything!<\/strong> If you think your fonts look good enough in light and dark mode, or you don\u2019t have the bandwidth right now to wrestle with reflow, element resizing, browser\/display inconsistencies, and extra CSS to maintain, then you may not have to change a thing. Focus on the rest of your site and leave yourself open to the possibility of revisiting this topic later.<\/p>\n\n\n

      Strategy 1: Reducing the font-weight<\/code> value<\/h3>\n\n\n

      Most variable text fonts have a weight axis, which lets us assign any specific font-weight<\/code> value within the weight range available to that font (e.g. 0-1000, 300-800, etc.). Each technique in this strategy takes advantage of this fine control over the weight axis to reduce font-weight<\/code> values in dark mode. (The need for such font-weight<\/code> precision is also what renders most non-variable fonts unsuitable for this solution.)<\/p>\n\n\n\n

      If you\u2019re using variable fonts you have locally, you can check their axes and value ranges at Wakamai Fondue<\/a>:<\/p>\n\n\n\n

      \"\"
      At Wakamai Fondue, you can view any local font\u2019s variable axes and ranges.<\/figcaption><\/figure>\n\n\n\n

      Keep in mind that, if you\u2019re using the @font-face<\/code> rule to load fonts, you should set a font-weight<\/code> range for each of them at the same time:<\/p>\n\n\n\n

      @font-face {\n  src: url('Highgate.woff2') format('woff2-variations');\n  font-family: 'Highgate';\n  font-weight: 100 900;\n}<\/code><\/pre>\n\n\n\n

      If you neglect this step, some variable fonts may not properly reflect specific font-weight<\/code> values in current Chromium browsers.<\/p>\n\n\n\n

      \"\"
      Dalton Maag Highgate\u2019s font-weight<\/code> set to 800 in Chrome without (left) and with (right) a font-weight<\/code> range specified in the @font-face<\/code> rule.<\/figcaption><\/figure>\n\n\n

      The basic solution: Manually entering each weight<\/h2>\n\n\n

      Here\u2019s the technique most of us may reach for. We create a dark mode media query in which we enter some font-weight<\/code> values that are a bit lower than their defaults.<\/p>\n\n\n\n

      \/* Default (light mode) CSS *\/ \nbody {\n  font-weight: 400;\n}\n\nstrong, b, th, h1, h2, h3, h4, h5, h6 {\n  font-weight: 700;\n}\n\n\/* Dark mode CSS *\/\n@media (prefers-color-scheme: dark) {\n  body {\n    font-weight: 350;\n  }\n\n  strong, b, th, h1, h2, h3, h4, h5, h6 {\n    font-weight: 600;\n  }\n}<\/code><\/pre>\n\n\n\n