Leading trim with font metrics

by phloe

HTML

<link href="https://fonts.googleapis.com/css2?family=Abril+Fatface&family=Inter:wght@700&family=Titillium+Web:wght@700&display=swap" rel="stylesheet">

<select id="select">
	<option value="fatface">Abril Fatface</option>
	<option value="inter">Inter</option>
	<option value="titillium">Titillium Web</option>
</select>

<main id="main" class="fatface">
  <article>
    <h3 class="text-crop">Trimming leading on text is easy as pie</h3>
    <span class="label"><span class="text-center text-size">Label</span></span>
    <p class="text-crop text-size">Lowercase letters are dominant in body text so cropping to x-height and setting the line-height as a multiple of that can make a lot of sense. You could even scale body text so that x-height matches a specific size.</p>
    <blockquote>
      <p class="text-crop text-size">
      &ldquo; In quas cetero sea, usu facilisi mnesarchum consectetuer ne.
      </p>
    </blockquote>
  </article>
  
  <section>
    <h4 class="text-crop">Default text centering</h4>
    <ul id="lineHeights">
      <li id="lineHeightTest">hello</li>
    </ul>
  </section>
</main>

CSS

body {
  margin: 0;
  padding: 1rem;
  background-color: #DDD;
}

select {
  margin-bottom: 1rem;
}

section {
  background-color: #FFF;
  padding: 2rem;
}

* + section {
  margin-top: 1rem;
}

section h4 {
  margin: 0; 
  --line-height: 1.125;
  line-height: var(--line-height);
  font-size: 2rem;
}

section ul {
  margin: 2rem 0 0;
  padding: 0;
}

section li {
  background: linear-gradient(0deg, #CCC, #CCC 1px, #EEE 1px, #EEE 2px);
  background-size: 100% 2px;
  list-style: none;
}

section li:after {
  content: "";
  display: block;
  border-top: 1px solid orange;
  opacity: 0.75;
  transform: translateY(calc(100% - 1em * (((var(--line-height, var(--line-height-normal)) - var(--line-height-normal)) / 2) + var(--descender))));
}

section li + li {
  margin-top: 1rem;
}

article {
  background-color: #FFF;
  padding: 2rem;
}
article + article {
  margin-top: 1rem;
}

h3 {
  margin: 0;
  --line-height: 1.125;
  line-height: var(--line-height);
  font-size: 3rem;
}

article > p {
  margin: 2rem 0 0;
  --text-size: 0.5;
  --text-line-height: 3.5;
  --text-height: var(--x-height);
}

h3 + p {
  margin-top: 3rem;
}

blockquote {
  margin: 3rem 2rem;
}

blockquote > p {
  margin: 0;
  --text-size: 1.25;
  --text-line-height: 1.25;
  font-style: italic;
}

.label {
  display: inline-block;
  vertical-align: top;
  margin-top: 0.5rem;
  padding: 0.25rem 0.5rem;
  background-color: #333;
  color: #FFF;
  line-height: 0.875rem;
  --text-size: 0.625;
  --text-line-height: 1.4;
}

/*  */
.text-size {
  --font-size: calc(var(--text-size) / var(--text-height, var(--cap-height)));
  font-size: calc(var(--text-unit, 1rem) * var(--font-size));
  --line-height: calc(var(--text-line-height, var(--line-height-normal)) * var(--text-height, var(--cap-height)));
  line-height: var(--line-height);
}

.text-center {
	display: inline-block;
	transform: translateY(calc(-1em * (((var(--line-height-normal) / 2) - var(--descender)) - (var(--text-height, var(--cap-height)) /...

JavaScript

select.onchange = (event) => {
  main.className = event.target.options[event.target.selectedIndex].value;
};


console.log("lineHeightTest", lineHeightTest);

const baseSize = 16;

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].forEach((inc) => {
	const lineHeightTestClone = lineHeightTest.cloneNode();
  const lineHeight = (baseSize + inc) / baseSize;
  lineHeightTestClone.id = lineHeightTest.id + Math.random();
  lineHeightTestClone.innerText = `${baseSize}px/${baseSize + inc}px`;
  lineHeightTestClone.style.lineHeight = lineHeight;
  lineHeightTestClone.style.fontSize = '1rem';
  lineHeightTestClone.style.setProperty("--line-height", lineHeight);
  lineHeightTest.parentNode.appendChild(lineHeightTestClone);
});