In the first edition of Art & Logic, I’ll explore typography systems and create a flexible SCSS prototype for typography using a modular typographical scale.

## The Goal

Ultimately, we want a mixin that will output the correct font size and line-height for an input position on the scale. We want a mixin that looks like this:

`type-setting(h4);`

## Setting up

Before we get started, let’s declare a few variables and functions to be used throughout the project.

First up is a utility function that will strip the units from any input measurements. For example, the function below will return `10`

with an input of `10rem`

```
/// Strips the unit from a number.
@function strip-unit($value) {
@return ($value / ($value * 0 + 1));
}
```

Next, we need a function to raise an input number to an input power.

```
/// Power function
@function pow($base, $exponents) {
$raised: 1;
@for $i from 1 through $exponents {
$raised: $raised * $base;
}
@return $raised;
}
```

Lastly, we need to define a few variables

- The base font size of the entire HTML file (1rem)
- The base font size of our content
- The line-height of our base font.
- The ratio used for the scale

```
$rem-size: 10px; // Measurement px
$ratio: 1.25; // Number 1.25 = major third
$base-txt-size: 18px; // Measurement px
$base-line-height: 1.6; // Number unitless
$txt-size: strip-unit($base-txt-size) / strip-unit($rem-size) + 0rem; //converts value to "rem"
$line-height: strip-unit($base-txt-size) * $base-line-height / strip-unit($rem-size) + 0rem; // converts raw value to "rem"
```

## Modular Scale

Good typographical systems employ the use of a modular scale to establish a series of harmonious font sizes that share a mathematical relationship.

To create a modular scale, you start with your base font size and multiply it by a ratio. This ratio is usually somewhere between 1 and 1.5. I highly recommend reading Exploring Responsive Type Scales on Medium for a more detailed look at modular scales, since we’ll be more focused on the logic of setting one up in SCSS.

### Steps

To make our lives much easier, let’s set up a simple SCSS map to hold the relational font sizes of each size of the text.

```
$type-scale: (
large: 5,
h1: 4,
h2: 3,
h3: 2,
h4: 1,
h5: 0,
h6: 0,
p: 0,
small: -1
);
@function type-scale( $input ) {
@return map-get( $type-scale, $input );
}
```

This function returns the position of the font size on the type scale. Here’s an example of the function in action:

`type-scale(h4); // Returns 1`

Now we need to generate a scale. The long hand way of doing this would look something like this:

```
$base: 18px;
$ratio: 1.25;
$-1: $base / $ratio; // 14.4px
$0: $base; // 18px
$1: $0 * $ratio; // 22.5px
$2: $1 * $ratio; // 28.13px
```

We multiply (or divide) each font size by the previous size and the ratio for the scale. You can see that calculating the scale mathematically isn’t the cleanest option since we end up with partial pixels. You’ll have to decide if that is a major problem in your project, but we’re going to accept this flaw for now.

### Lots of math

We’re going to tidy up that logic and build our first function. This is where our power function comes into play.

```
@function type-size($input: null) {
$steps: null;
@if type-of($input) == string {
$steps: type-scale($input);
}
@else {
$steps: $input;
}
@if $steps == 0 {
@return $txt-size;
}
@else if $steps < 0 {
$steps: $steps * -1;
@return strip-unit($txt-size) / pow( $ratio, $steps ) + 0rem;
}
@else {
@return strip-unit($txt-size) * pow( $ratio, $steps ) + 0rem;
}
}
```

Ok, I know this is kind of long so I’ll explain what is happening step by step. First, we can input a raw number of steps to multiply by, or we can input a font size from our map above.

```
@if type-of($input) == string {
$steps: type-scale($input);
}
@else {
$steps: $input;
}
```

We check the input to see if it is a string and assign the value it matched on the scale. If it’s not a string, we pass the input directly through to the function.

If the number of steps is equal to 0, we return the base font size.

```
@if $steps == 0 {
@return $txt-size;
}
```

Next, we see if the number of steps is negative. If so, we remove the negative notation from the value and divide.

```
@else if $steps < 0 {
$steps: $steps * -1;
@return strip-unit($txt-size) / pow( $ratio, $steps ) + 0rem;
}
```

Lastly, if the code has reached this point, we know the number of steps must be positive, so we’ll multiply the text size by its position on the scale.

```
@else {
@return strip-unit($txt-size) * pow( $ratio, $steps ) + 0rem;
}
```

Lots of math, but we have the core logic behind the type scale. As an example, here’s how we could use the function to define the font size of the largest header:

`type-size(h1) // Returns 43.95rem`

The benefits of this system are that it allows us to change the base font size or the ratio at any time without having to do the math all over again.

## Vertical Rhythm

Having font sizes is great, but we also need to calculate line heights if we want to maintain a nice vertical rhythm. As a general rule, you can maintain vertical rhythm by making sure every vertical measurement (line-heights, paddings, margins, etc) are all a multiple of the base line-height.

This time, we’ll be getting the calculated line-height from an input font size. There’s a catch though, we also want to be able to input a value from our type scale map above.

```
@function line-height( $input: $font-size ) {
$size: null;
$value: strip-unit( $line-height );
$i: 1;
@if type-of($input) == string {
$size: type-size($input);
}
@else {
$size: $input;
}
$size: strip-unit( $size );
@while $value < $size {
$value: strip-unit( $line-height ) * $i;
$i: $i + 0.5;
}
@return $value + 0rem;
}
```

Once again, we have a little bit of logic to walk through. First, we have to determine the input font size. We check if the input is a string, which means it is a value from the scale map and get the type size from that function if true. Otherwise, we can pass the input through as the size of the text. In either case, we also need to strip the unit from the text size and use unitless numbers in the math.

```
@if type-of($input) == string {
$size: type-size($input);
}
@else {
$size: $input;
}
$size: strip-unit( $size );
```

Now we start a loop. This will multiply the line height by 0.5 each iteration until the line height is greater than or equal to the input font size. Then add the rem unit back to the value and return it.

```
@while $value < $size {
$value: strip-unit( $line-height ) * $i;
$i: $i + 0.5;
}
@return $value + 0rem;
```

## Bringing it all together

We now have two great mixins that can help us calculate the font size and line-height of the text according to a number of variables. But we can take it one step further and make a simple mixin to apply both of these at once.

```
@mixin type-setting( $input ) {
font-size: type-size( $input );
line-height: line-height( $input );
}
```

In use, we can now have a statement like this:

```
:root {
font-size: $rem-size;
}
.u-h3 {
@include type-setting(h3);
}
```

Which should render out to this in vanilla CSS:

```
:root {
font-size: 10px;
}
.u-h3 {
font-size: 28.13rem;
line-height: 32rem;
}
```

## Final Thoughts

This was a fun and really useful project to make. It can still be greatly improved to allow for responsive design and could use error handling in case bad values are passed in. Typography is a deep and very complicated topic, but a strong system like this can help you get something nice set up really quick and allow for rapid experimentation.

In future explorations, I want to look at a similar system from the idea of fluid typography. For now though, you can check out the full source code for this project (including error handling) in my GitHub gist.