How to create responsive typography using CSS — Three different methods explained
Tags: css, html, tutorial, webdev
Published: 2021-01-20 20:52:14

Good typography is one of the key elements of a website. Let's take a look at **three different methods** on **how to create responsive typography using CSS**.

**The three methods are:**

1. Responsive typography using **only media queries**
1. Responsive typography using **a CSS custom property as a multiplier**
1. Responsive typography using **the CSS clamp() function**

**TL;DR:** Check out the final [Codepen with all the methods](https://codepen.io/laurilllll/pen/ZEWZvBg). Resize the viewport to see the effect.

---

### Why should you use responsive typography?

The web is used on various screen sizes. Your site has to work on **mobile**, **tablet**, **laptop**, **desktop** and basically everything in between so there's a lot to take into consideration.

> All of the method examples below are **simplified** as they only cover **three selectors** and **one breakpoint**.

You can use this simple **HTML** to try out all the methods in this tutorial:

```html
<h1>How to create responsive typography using CSS</h1>
<p>
  Vestibulum molestie sapien eget orci pellentesque, et aliquam lectus convallis. Phasellus neque velit, ultricies ut lacus at, finibus lobortis dui. Proin eget diam elit.
</p>
<h2>Three different methods explained</h2>
<p>
  Pellentesque sagittis nisl nec rhoncus porta. Quisque luctus turpis nec turpis consequat fermentum et vitae diam.
</p>
```

*Let's dig in!*

---

## Method 1: Responsive typography using only media queries

This is the most basic method in our list.

Simply, **declare your text styles** and **increase the font-size on bigger screens** using a breakpoint:

```css
/* Declare text styles */
h1 {
  font-size: 2em;
}
h2 {
  font-size: 1.5em;
}
p {
  font-size: 1em;
}

/* Increase font sizes by 1.5x on bigger screens */
@media (min-width: 48rem) {
  h1 {
    font-size: 3em;
  }
  h2 {
    font-size: 2.25em;
  }
  p {
    font-size: 1.5em;
  }
}
```

Check out the result from this [Codepen](https://codepen.io/laurilllll/pen/bGwJbJb). Resize the viewport to see the effect.

{% codepen https://codepen.io/laurilllll/pen/bGwJbJb default-tab=css,result %}

Using this method is totally fine and it does the job very well.

The **downside is the large amount of code** you have to write. The codebase gets larger with every new selector you need to add. You have to write the styles **separately** for **every selector in each breakpoint**.

> In a real world you would probably have text selectors **h1**, **h2**, **h3**, **h4**, **h5**, **h6**, **p** and at least **two breakpoints**. At that point, this code is would've already gone **from 20 lines to 67 lines**. That's **3.35x** increase in the amount of code.

The next method will show how to **decrease the code amount** and make it **easier to maintain!**

---

## Method 2: Responsive typography using a CSS custom property as a multiplier

**CSS custom properties** (variables) are super powerful. In the previous method, we increased the font sizes *manually* one selector at a time. Now, we'll **declare a multiplier variable** for the font-sizes and only **increase the value of the multiplier** inside a breakpoint.

Let's look at the code example in full and then break it down:

```css
/* Declare a font size multiplier variable */
:root {
  --text-multiplier: 1;
}

/* Increase the size of the multiplier on bigger screens */
@media (min-width: 48rem) {
  :root {
    --text-multiplier: 1.5;
  }
}

/* Declare text styles using calc() function and the multiplier */
h1 {
  font-size: calc(2em * var(--text-multiplier));
}
h2 {
  font-size: calc(1.5em * var(--text-multiplier));
}
p {
  font-size: calc(1em * var(--text-multiplier));
}
```

Check out the result from this [Codepen](https://codepen.io/laurilllll/pen/ZEpZzPB). Resize the viewport to see the effect.

{% codepen https://codepen.io/laurilllll/pen/ZEpZzPB default-tab=css,result %}

**The first step** is to **declare a variable** that we use to control our font size later on. We set the default value to **1**.

```css
:root {
  --text-multiplier: 1;
}
```

**The second step** is to **increase the multiplier value** inside a breakpoint. Unlike SASS variables, CSS custom properties **can be used inside media queries**.

```css
@media (min-width: 48rem) {
  :root {
    --text-multiplier: 1.5;
  }
}
```

**The last step** is to declare our font-sizes but this time we use **the calc() function** so we can utilise our **multiplier**.

```css
h1 {
  font-size: calc(2em * var(--text-multiplier));
}
h2 {
  font-size: calc(1.5em * var(--text-multiplier));
}
p {
  font-size: calc(1em * var(--text-multiplier));
}
```

As you can see, **we only need to declare our font sizes once**. This is a huge improvement compared to the first method.

> Compared to the first method, we only have **17 lines of code compared to 20**. If we would add four more selectors and one breakpoint, our code would **only increase from 17 lines to 34**. Remember that using the first method it would require **67 lines**. Almost twice as much.

The decrease of code is due to our elegant way of using a **CSS custom property as a multiplier**. Adding another breakpoint takes only **three lines of code** because we don't have to modify our font sizes at all. The code is also a lot **easier to maintain and modify**.

Adding breakpoints is as simple as:

```css
/* Add more breakpoints */
@media (min-width: 64rem) {
  --text-multiplier: 1.75;
}
@media (min-width: 80rem) {
  --text-multiplier: 2.0;
}
```

To the user, this methods **looks exactly the same** as the first but **the code is much better**.

Next up, we'll take a look at a **new CSS clamp() function**.

---

## Method 3: Responsive typography using the CSS clamp() function

The **clamp() function** is pretty powerful! You can set a value using three parameters: **a minimum value**, **a preferred value** and **a maximum value**. Basically you'll have a 3-in-1 value!

Example declaration for responsive text using the **clamp() function** looks like this:

```
font-size: clamp(2rem, 5vw, 3rem);
```

This allows us to create responsive typography **without any media queries**. **With only one line of code** we set the minimum value (mobile), the maximum value (desktop) and the preferred value.

**The font size will become fluid** as it will always be the **preferred value inside the min-max range**. Very powerful!

To set the responsive typography for our demo, it is as simple as this:

```css
/* Declare text styles */
h1, h2, p {
  /* Font minimum, preferred and maximum value */
  font-size: clamp(var(--min), var(--val), var(--max));
}

/* Font size variables */
h1 {
  --min: 2em; /* minimum value */
  --val: 5vw; /* preferred value = 5% viewport width */
  --max: 3em; /* maximum value */
}
h2 {
  --min: 1.5em;   /* minimum value */
  --val: 4vw;     /* preferred value = 4% viewport width */
  --max: 2.25em;  /* maximum value */
}
p {
  --min: 1em;   /* minimum value */
  --val: 2.5vw; /* preferred value = 2.5% viewport width */
  --max: 1.5em; /* maximum value */
}
```

Check out the result from this [Codepen](https://codepen.io/laurilllll/pen/ExgJYRm). Resize the viewport to see the effect.

{% codepen https://codepen.io/laurilllll/pen/ExgJYRm default-tab=css,result %}

If you look at the code, you'll see that by using **CSS custom properties together with the clamp() function** we are able to **declare all the text styles at the same time with only on line of code**.

After that, we just set the **--min**, **--val** and **--max** custom properties for each selector and we are done!

> CSS custom properties can be **scoped inside selectors** so you can **use the same custom properties with multiple selectors** just like we have done here with our **h1**, **h2** and **p**. These custom properties will not clash together even though they have the same name.

This method takes up 18 lines of code and with four more selectors and one breakpoint it would be 38 lines. So, it's slightly larger than on the second method but we get **fluid typography** in return.

**Note:** The **clamp() function** is pretty new, so you should check if it has the browser support you need from [caniuse.com](https://caniuse.com/css-math-functions).

---

## Wrap up

**CSS is powerful!**

In many cases, there's more than one way to achieve the desired result.

If you read this far, thank you! I hope you learned something new.

Here's the final [Codepen with all the methods](https://codepen.io/laurilllll/pen/ZEWZvBg) once more. Resize the viewport to see the effect.

{% codepen https://codepen.io/laurilllll/pen/ZEWZvBg default-tab=css,result %}

---

## Thank you 🙏

I hope you found this article helpful 🔥

You can [follow me on Twitter](https://twitter.com/laurilllll) for more **CSS**, **Design System** and **Figma** content 💪