htmlcsstypographyletter-spacing

Letter spacing in CSS changes word spacing?


I've observed that when I adjust the letter spacing in CSS, the word spacing seems to change automatically. However, after extensive research, I couldn't find concrete information on this relationship.

Background: I consulted various resources, including ChatGPT 4.0, and the consensus appears that letter and word spacing are independent properties. I've tested this behavior across multiple fonts and browsers and consistently noticed the change.

This behavior differs from vector-based graphic design software like CorelDRAW, where adjusting letter spacing doesn't impact word spacing. I like the browser's approach and feel it produced an authentically pleasing result. It perfectly reduces the word spacing as letter spacing decreases.

Question: Is this word spacing adjustment in browsers when letter spacing is modified a recognized phenomenon? Chat GBT says it shouldn't happen, and they're independent properties. One does not change the other. I can't find any information online about this topic.

I have validated it across different fonts and browsers. The decrease or increase in word spacing is proportionate to letter spacing and is the same regardless of font.

<!DOCTYPE html>
<html>
<head>
<style>
h1{
  letter-spacing: 20px;
  font-size: 20px;
}

h2 {
  letter-spacing: 10px;
  font-size: 20px;
}

h3 {
  letter-spacing: 5px;
  font-size: 20px;
}
span {
  border-style: solid;
}
</style>
</head>
<body>

<h1><span>This</span> <span>is</span> <span>heading</span> <span>1</span></h1>
<h2><span>This</span> <span>is</span> <span>heading</span> <span>2</span></h2>
<h3><span>This</span> <span>is</span> <span>heading</span> <span>3</span></h3>

</body>
</html>


Solution

  • Sample showing individual glyph rectangles:

    // "lettering"
    document.querySelectorAll('div > *').forEach(
     h => h.innerHTML = [...h.innerHTML].map(c => `<span data-char="${c}">${c}</span>`).join('')
     );
    
    // append computed width
    document.querySelectorAll('span').forEach(
     s => s.insertAdjacentHTML('beforeend', `<samp>${s.getBoundingClientRect().width}</samp>`)
    );
    div > * {
     margin-top: 0;
     line-height: 2;
    }
    div span {
     border-top: 1rem solid #000;
     position: relative;
    }
    div span:nth-child(even) {
      border-top-color: #999;
    }
    samp {
      position: absolute;
      bottom: 100%;
      left: 0;
      font-size: 1rem;
      letter-spacing: 0;
      line-height: 1rem;
      background-color: #000;
      z-index: 1;
    }
    div span:nth-child(even) samp {
      color: black;
      background-color: #9996;
    }
    
    div:not(:hover) span:not([data-char=" "]) samp {
     opacity: 0;
     z-index: 0;
    }
    
    div:hover span:not(:hover) samp {
      opacity: 0;
    }
    html {
      background-color: #333;
      color: #ccc;
    }
    body:hover span:not(:hover) {
     opacity: .1;
    }
    <div>
      <p style="font-size: 20px;
                letter-spacing: 20px;"
      >20px font 20px spacing</p>
      <p style="font-size: 20px;
                letter-spacing: 10px;"
      >20px font 10px spacing</p>
      <p style="font-size: 20px;
                letter-spacing: 5px;"
      >20px font 5px spacing</p>
      <p style="font-size: 20px;
                letter-spacing: 0px;"
      >20px font 0px spacing</p>
      <p style="font-size: 12px;
                letter-spacing: 12px;"
      >12 px font 12 px spacing</p>
      <p style="font-size: 12px;
                letter-spacing: 0px;"
      >12px font 0px spacing</p>
    </div>

    For me renders:

    Sample texts, each glyph has top border of alternating colour, spaces display number of pixels, as described in further text below.

    This shows that intrinsic "space" width for 20px is 5px and letter-spacing (20, 10, 5 and 0 px) is simply added to it, producing 25 15 10 and 5 pixels wide glyphs. Same applies for example for the zero digit that is 10px wide and with added letter-spacing gets widths 30, 20, 15 and 10 respectively.

    It makes sense, because if letter-spacing was only added to non-white-space glyphs, you'd have to remember to adjust word-spacing all the times you touch it: for example for letter-spacing: 10px; font-size: 20px; you'd get gaps between glyphs twice as wide as gaps between words, in this hypothetical case, what presumably is not what you'd expect.