Skip to content

Instantly share code, notes, and snippets.

@robweychert
Last active October 26, 2021 13:21
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robweychert/46b666c096902f578bd41bb47a5cdd43 to your computer and use it in GitHub Desktop.
Save robweychert/46b666c096902f578bd41bb47a5cdd43 to your computer and use it in GitHub Desktop.
Sass typographic scale generator

Sass typographic scale generator

Generate a typographic scale of CSS variables with any interval (fixed or proportional) and any number of sizes. Just edit $interval, $body-text, $scale-min, and $scale-max:

:root {
  $interval: 1.5;    // Unitless for proportional, unit for fixed
  $body-text: 1rem;  // Must have a unit
  $scale-min: -2;    // Unitless negative integer
  $scale-max: 2;     // Unitless positive integer

  --int: #{$interval};
  --scale0: #{$body-text};

  @if $scale-min < 0 {
  // Generate scale variables smaller than the body text size
    @for $i from -1 through $scale-min {
      @if type-of($interval) == number {
        @if unitless($interval) {
          --scale#{$i}: calc(var(--scale#{$i + 1}) / var(--int));
        } @else {
          --scale#{$i}: calc(var(--scale#{$i + 1}) - var(--int));
        }
      }
    }
  }
  @if $scale-max > 0 {
    // Generate scale variables larger than the body text size
    @for $i from 1 through $scale-max {
      @if type-of($interval) == number {
        @if unitless($interval) {
          --scale#{$i}: calc(var(--scale#{$i - 1}) * var(--int));
        } @else {
          --scale#{$i}: calc(var(--scale#{$i - 1}) + var(--int));
        }
      }
    }
  }
}

The Sass above generates this CSS:

:root {
  --int: 1.5;
  --scale0: 1rem;
  --scale-1: calc(var(--scale0) / var(--int));
  --scale-2: calc(var(--scale-1) / var(--int));
  --scale1: calc(var(--scale0) * var(--int));
  --scale2: calc(var(--scale1) * var(--int));
}

For more details, see my 24 Ways article, A Modern Typographic Scale.

@jonathanstegall
Copy link

Do you have any insights about how to calculate line-height when using this for font sizes?

@robweychert
Copy link
Author

robweychert commented Feb 12, 2020

@jonathanstegall Using unitless values for line-height will get you pretty far, since you can set it once and it will be proportional to the font-size. So when the font-size changes, the line-height doesn’t need to:

body {
  line-height: 1.5;
}
h1 {
  font-size: 32px; /* line-height = 48px */
}
p {
  font-size: 16px; /* line-height = 24px */
}

This is not to say that all type in all contexts should use the same proportional line-height, which an excellent post by Frank Chimero touched on recently. So, if you want line-height proportions to track with your typographic scale, you could use the scale-building techniques outlined in my 24 Ways article with just the interval, no rems:

:root {
  --int: 1.5;
  --lh0: var(--int);                       /* 1.5 */
  --lh-1: calc(var(--lh0) / var(--int));   /* 1.0 */
  --lh-2: calc(var(--lh-1) / var(--int));  /* 0.666666666666667 */
  --lh1: calc(var(--lh0) * var(--int));    /* 2.25 */
  --lh2: calc(var(--lh1) * var(--int));    /* 3.375 */
}

As you may have noticed, only a few of the values in that scale are really viable as line-height values, so this approach generally works better with a smaller interval. That said, chances are you won’t need more than two or three line-height proportions for whatever you’re doing.

@jonathanstegall
Copy link

@robweychert thanks for the detailed response!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment