<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
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.