How to create responsive typography using CSS — Three different methods explained
Lauri Lännenmäki
Posted on January 20, 2021
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:
- Responsive typography using only media queries
- Responsive typography using a CSS custom property as a multiplier
- Responsive typography using the CSS clamp() function
TL;DR: Check out the final Codepen with all the methods. 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:
<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:
/* 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. Resize the viewport to see the effect.
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:
/* 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. Resize the viewport to see the effect.
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.
: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.
@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.
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:
/* 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:
/* 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. Resize the viewport to see the effect.
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.
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 once more. Resize the viewport to see the effect.
Thank you 🙏
I hope you found this article helpful 🔥
You can follow me on Twitter for more CSS, Design System and Figma content 💪
Posted on January 20, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.