Fluid Typography
Tags: css, webdev, tutorial, a11y
Published: 2023-09-11 15:15:13

*Photo by Ross Findon in Unsplash*

> You can access this article in Portuguese [here](https://dev.to/marcelluscaio/tipografia-fluida-104n)
> Você pode acessar este artigo em português [aqui](https://dev.to/marcelluscaio/tipografia-fluida-104n)


  
## A promise is a debt


A few days ago, [I wrote about some typography tips](https://dev.to/marcelluscaio/using-rem-doesnt-make-your-website-responsive-heres-why-4b0e). We discussed the importance of using the REM unit and how to make our fonts responsive using Media Queries. With that, you can already create impeccable web projects in terms of font size. But I promised to talk about making fonts responsive without using Media Queries, and a promise is a debt. So, here we go!


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lly5ctf7jqgs8zjg9fy0.jpg)

## The limits of Media Queries

When we adapt font sizes using media queries, our fonts remain the same size until they reach the breakpoint, and only then they change.

Open the CodePen below and adjust the screen width to see the sudden change in font size.

{% codepen https://codepen.io/marcelluscaio/pen/XWopvde %}
[Open the CodePen in another tab.]( https://codepen.io/marcelluscaio/pen/XWopvde)

Using the fluid typography technique, our font will always adjust to the screen size. For every pixel the screen increases, there will be an increment in font size.

"Caio, what kind of witchcraft is this? How is that possible?"

It's not witchcraft, but a powerful CSS function: clamp().


## Getting to know 'clamp()'

With clamp(), we can define a minimum value, an ideal value, and a maximum value.

Let's say we want our font to be 16px on a screen width of 320px and 32px on a screen width of 1920px. Our clamp() would look something like this:

```css
clamp(1rem, valor ideal, 2rem);

/*
You noticed that we're using REM, right?
No PX for fonts, remember?
*/
```

What about the ideal value? Well, since we want our font to adapt to the screen size, we'll use one of the viewport units, VW. 100vw is the size of the screen, and 1vw is 1% of the screen width. On a 320px screen, 100vw is 320px, and 1vw equals 3.2px.

Let's temporarily use the value of 5vw.

```css
clamp(1rem, 5vw, 2rem)
```

With this, our font still has those minimum and maximum limits of 16px and 32px (based on the browser's default font), but with 5vw as the ideal value, it will always try to be 5vw in size.

Let's see some examples:

> On a 300px screen: 5vw would be 15px. 15px is less than 16px - our minimum font size. In this case, the font would be 16px.

> On a 320px screen: 5vw would be 16px. The font used would be 16px.

> On a 500px screen: 5vw would be 25px. 25px is greater than 16px, and it's less than the maximum limit of 32px. So, the font used would be 25px.

> On a 1000px screen: 5vw would be 50px. Since this value is greater than our limit, the font used would be 32px.

See this applied in the example below:

{% codepen https://codepen.io/marcelluscaio/pen/eYbvYyZ %}

[Open the CodePen in another tab.]( https://codepen.io/marcelluscaio/pen/eYbvYyZ)


### Not everything is perfect

We have two problems here:

1) Our font is growing too quickly in this example. It reached our limit at a screen width of 640px, but we wanted it to vary fluidly up to 1920px. It becomes static for 1280px! 

2) Using a font based solely on viewport units poses an accessibility problem. Try going back to the previous CodePen and zoom in on the screen. Users cannot zoom in on the font, which remains frozen since it's based on the screen size. You'll notice that the text in the center of the screen doesn't change in size, while the screen and font size counter in the upper-left corner increases.


## Using VW + REM

A technique that helps with these two problems is to define the ideal value, the one in the middle of the clamp(), not just in VW, but as a sum of VW and REM.

Let's use the following values:

```css
clamp(1rem, .8rem + 1vw, 2rem)
```

See in the example below that the font starts to grow exactly after 320px and stops just before 1920px!

{% codepen https://codepen.io/marcelluscaio/pen/MWZpYwJ %}

[Open the CodePen in another tab.]( https://codepen.io/marcelluscaio/pen/MWZpYwJ)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fgq82nvo82r82fhvy5et.gif)

"Caio, you're a genius! How did you come up with that value?"

I hate to disappoint you, dear reader, but I didn't do this calculation in my head! There is a formula to calculate this ideal value, and all the explanations for that will be in one of the articles I'll leave in the references. In this example and in my daily work, I use a tool that calculates it for me.

[You can access this tool here.](https://utopia.fyi/type/calculator)


### The Fluid Type Calculator


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2exkk76jg2ft60qinjnl.png)

Here, we can define the minimum and maximum screen widths and the minimum and maximum font sizes — let's just ignore the Type Scale option for now.

The tool provides the clamp() values for you. Then, just add them to your code, and you're good to go.


### Dealing with multiple font sizes simultaneously

> "Caio, I've never worked on a project with just one font size!"

I know, I know. The example with only one font size was to make things simple. But there's no catch 22 here. Let's apply this logic to our first example, the one with fonts using Media Queries.

There, we had the following font model:

Level 1 -> 16px to 18px;

Level 2 -> 20px to 24px;

Level 3 -> 25px to 32px;

Level 4 -> 31px to 42px;

Now we just need to use our calculator for each of these ranges!

Previously, we had:

```css
:root{
  --fs-1: 1.125rem;
  --fs-2: 1.5rem;
  --fs-3: 2rem;
  --fs-4: 2.625rem
}

@media (max-width: 40em){
  :root{
    --fs-1: 1rem;
    --fs-2: 1.25rem;
    --fs-3: 1.5625rem;
    --fs-4: 1.9375rem
  }
}
```

Now we end up with this:

```css
:root{
  --fs-1: clamp(1.00rem, calc(0.98rem + 0.13vw), 1.13rem);;
  --fs-2: clamp(1.25rem, calc(1.20rem + 0.25vw), 1.50rem);
  --fs-3: clamp(1.56rem, calc(1.48rem + 0.44vw), 2.00rem);
  --fs-4: clamp(1.95rem, calc(1.81rem + 0.71vw), 2.66rem)
}
```

See the example below:

{% codepen https://codepen.io/marcelluscaio/pen/VwqpYdO %}

[Open the CodePen in another tab.]( https://codepen.io/marcelluscaio/pen/VwqpYdO)



## Ok, what about the Type Scale Thing?

As developers, we often don't take part in the font size selection process. Designers usually lead that decision. "And how do they do that?", you might be wondering.

That's a science of its own. There are different systems: the 4-point grid, the 8-point grid, Google's Material Design, and many others. None of these systems can do without the trained eyes of design professionals: systems are not magic and often require adaptations.

One of these systems is modular scale typography. In this system, we start with a font size and increase or decrease it based on a multiplication factor. For example, let's say our smallest font is 10px, and the multiplication factor is 2. Our font system could have the following values: 10px, 20px, 40px, 80px, and so on. This example is exaggerated for didactic purposes, of course.

This methodology adds objectivity to font size selection and helps make our typography hierarchy more consistent.

The Type Scale field in our calculator helps generate fonts using this type of methodology. Let's say I have a project with 4 font levels (4 different sizes), and the smallest font should be 14px on mobile and 20px on monitors.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9dkwqsii1rncstt1uh46.png)

Here, I'm applying a growth rate of 1.25 on 320px screens while applying a growth rate of 1.414 on 1900px screens. The result is as follows:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtl9wqlpbpl5g383h2xu.png)

Note that font sizes grow much faster on the 1900px screen because we used a higher rate. I invite you to read the excellent articles on modular typography scales that will be in the references of this article to better understand when to choose which rate for your scale. I also encourage you to generate and test different scales and compare the results. What happens when the scale rate is higher on larger screens than on smaller screens? What happens when the rate is the same? And when it's smaller?

## Conclusion

We've learned how to apply the fluid typography technique using CSS. Fluid typography is an elegant solution that brings visual integrity to your project on various screens.

Always remember that accessibility is a priority. To ensure your website is accessible, always test it with a 200% zoom.


## References

Kevin Powell - Simple solutions to responsive typography
https://www.youtube.com/watch?v=wARbgs5Fmuw

Modern Fluid Typography Using CSS Clamp
https://www.smashingmagazine.com/2022/01/modern-fluid-typography-css-clamp/

Generating `font-size` CSS Rules and Creating a Fluid Type Scale
https://moderncss.dev/generating-font-size-css-rules-and-creating-a-fluid-type-scale/

Responsive Type and Zoom
https://adrianroselli.com/2019/12/responsive-type-and-zoom.html

Resize text
https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-scale.html

Should I change the default HTML font-size to 62.5%?
https://fedmentor.dev/posts/rem-html-font-size-hack/

4-Point Grid System for more consistent interface design
https://medium.com/@aratidube12lns/4-point-grid-system-for-more-consistent-interface-design-efea81dea3f3

More Meaningful Typography
https://alistapart.com/article/more-meaningful-typography/

Um guia prático para criar um tipo de escala modular para suas interfaces
https://www.ux-republic.com/pt/guia-pr%C3%A1tico-para-criar-um-tipo-de-escala-modular-para-suas-interfaces/