<section>
  <header>
    <h2>Un-Adjusted</h2>
    <h1>Perceived font weight based on light/dark preference</h1>
  </header>
  <p>Humans perceive white on black vs black on white differently.</p> 
  <p>In dark mode, the light colored font appears to be thicker or glow a bit more, even though weight and <abbr title="grade: adjust the stroke thickness of a typeface without changing its width, spacing, or kerning">GRAD</abbr> are unchanged. The CSS in this demo counterbalances that by using the font's <abbr title="grade: adjust the stroke thickness of a typeface without changing its width, spacing, or kerning">GRAD</abbr> axis and a negative value, shrinking the perceived thickness of the font <b>without affecting layout</b>.</p>
  <p>Subtle, but appreciated.</p>
</section>

<div class="controls">
  <fieldset id="colorscheme">
    <legend>Color Scheme</legend>
    <div>
      <label>
        <input type="radio" name="colorscheme" value="light">
        Light
      </label>
    </div>
    <div>
      <label>
        <input type="radio" name="colorscheme" value="dark" checked>
        Dark
      </label>
    </div>
  </fieldset>
  <fieldset id="grad">
    <legend>GRAD</legend>
    <div>
      <input type="range" min="-200" max="150" value="-100">
      <output>-100</output>
    </div>
  </fieldset>
</div>

<section class="adjusted" id="adjusted">
  <header>
    <h2>Adjusted</h2>
    <h1>Perceived font weight based on light/dark preference</h1>
  </header>
  <p>Humans perceive white on black vs black on white differently.</p> 
  <p>In dark mode, the light colored font appears to be thicker or glow a bit more, even though weight and <abbr title="grade: adjust the stroke thickness of a typeface without changing its width, spacing, or kerning">GRAD</abbr> are unchanged. The CSS in this demo counterbalances that by using the font's <abbr title="grade: adjust the stroke thickness of a typeface without changing its width, spacing, or kerning">GRAD</abbr> axis and a negative value, shrinking the perceived thickness of the font <b>without affecting layout</b>.</p>
  <p>Subtle, but appreciated.</p>
</section>
@font-face {
  font-family: "Roboto Flex";
  src: url('https://assets.codepen.io/2585/RobotoFlex') format('truetype');
}

@layer demo {
  .adjusted {
    --font-grade--light: 0;
    --font-grade--dark: -50;
    --font-grade: var(--font-grade--light);
    
    font-variation-settings: "GRAD" var(--font-grade);
  }
  
  @media (prefers-color-scheme: light) {
    #grad { opacity: 0 }
  }
  
  @media (prefers-color-scheme: dark) {
    .adjusted {
      --font-grade: var(--font-grade--dark);
    }
  }
  
  html:has(#colorscheme [value="light"]:checked) {
    color-scheme: light;
    
    .adjusted {
      --font-grade: var(--font-grade--light);
    }
    
    #grad { opacity: 0 }
  }
  
  html:has(#colorscheme [value="dark"]:checked) {
    color-scheme: dark;
    
    .adjusted {
      --font-grade: var(--font-grade--dark);
    }
  }
}

@layer demo.support {
  html {
    color-scheme: light dark;
    height: 100%;
    display: grid;
  }
  
  body {
    display: grid;
    place-content: center;
    padding: 5vmin 1.5rem;
    gap: 10vh;
    font-family: Roboto Flex;
    
    @media (width >= 1500px) {
      grid-auto-flow: column;
      place-items: center;
    }
  }
  
  section {
    display: grid;
    gap: 1.5lh;
    
    > header {
      display: grid;
      gap: .75lh;
      
      > h2 {
        opacity: .75;
        text-transform: uppercase;
      }
    }
  }
  
  h1, h2, p {
    margin: 0;
    text-box: trim-both cap alphabetic;
  }
  
  h1 {
    max-inline-size: 30ch;
    text-wrap: balance;
    line-height: 1.25;
  }
  
  p {
    max-inline-size: 60ch;
    text-wrap: pretty;
    line-height: 1.5;
  }
  
  .controls {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1lh;
  }
  
  #colorscheme {
    > div {
      display: inline-flex;
      
      &:first-of-type {
        margin-inline-end: 2ch;
      }
    }
    
    label {
      display: flex;
      place-items: center;
      gap: .5ch;
      
      input {
        margin: 0;
      }
    }
  }
  
  #grad {
    transition: opacity 1s ease;
    
    > div {
      display: flex;
      place-items: center;
      gap: 1ch;
    }
  }
}
grad.oninput = e => {
  let value = e.target.value
  
  adjusted.style.setProperty('--font-grade--dark', value)
  grad.querySelector('output').textContent = value
}
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.