Instead of setting media query breakpoints, use fluid typography to create a more "fluid" (or gradual) transition between font sizes and line heights that change proportionally according to the width of the viewport.

A combination of mathematics and CSS's `clamp()`

function are used to achieve this effect.

### Responsive Font Size

In responsive web design, we use media query breakpoints in order to make a website's content respond in a certain way depending on the viewport's width.

Consider the following example of responsive font size :

```
@media (max-width: 414px) {
h1 {
font-size: 16px;
}
}
@media (min-width: 415px) and (max-width: 768px) {
h1 {
font-size: 32px;
}
}
@media (min-width: 769px) {
h1 {
font-size: 48px;
}
}
```

The CSS defines the `font-size`

property of the `h1`

element when the viewport is at various breakpoints.

- For viewports up to
`414px`

wide, the font size is`16px`

. - For viewports between
`415px`

and`768px`

, the font size is`32px`

. - For viewports of at least
`769px`

wide, the font size is`48px`

.

This responsive approach causes the font size to "jump" from `16px`

to `32px`

when the viewport's width goes from `414px`

to `415px`

. This "jump" from one font size to another also happens when the width goes from `768px`

to `769px`

, or from `769px`

to `768px`

, or from `415px`

to `414px`

.

### Basic Fluid Font Size

One way to avoid this "jump" side effect (and achieve a more "fluid" effect, instead) is to use the viewport's current width — as opposed to using predefined breakpoints — when setting the font size. We can do this by using CSS's viewport unit for width: `vw`

.

There are four viewport-based units in CSS:

`vw`

`vh`

`vmin`

`vmax`

`vw`

is a relative length unit representing a percentage of the viewport's width. For example, `50vw`

is 50% of the viewport's width. So, given a viewport that is `1280px`

wide, `50vw`

means 50% of that `1280px`

, which is `640px`

You can learn more about viewport-based units on the MDN Web Docs .

Let's update our example and set the `font-size`

property of the `h1`

element to `10vw`

:

```
h1 {
font-size: 10vw;
}
```

As the viewport's width changes, the value of the font-size property adjusts proportionally:

- When the viewport's width is
`400px`

, the font-size property is set to 10% of`400px`

, which is`40px`

. - When the viewport's width is
`800px`

, the font-size property is set to 10% of`800px`

, which is`80px`

.

The changes to the font size will now present with fluidity.

### Intermediate Fluid Font Size

One drawback to setting the value of the `font-size`

property to a `vw`

unit is precision control. What if you wanted the font size to be:

`32px`

when the viewport's width is`414px`

,`48px`

when the viewport's width is`768px`

, and- proportionally in between
`32px`

and`48px`

when the viewport's width is in between`414px`

and`768px`

?

A simple assignment of a `vw`

value to the font-size property is no longer an option. Instead, we need to use a combination of CSS's `calc()`

function and a couple of mathematical formulas.

According to the MDN Web Docs,

`The ``calc()`

CSS function lets you perform calculations when specifying CSS property values.

And for the purpose of fluid font size, the `calc()`

function will suffice.

The first mathematical formula we need to be aware of is the point-slope form equation of a line:

`y - y`_{1} = m(x - x_{1})

Where:

`y`

= y coordinate of the second point`y`

= y coordinate of the first point_{1}`m`

= slope of the line formed by the two points with coordinates (x, y) and (x_{1}, y_{1})`x`

= x coordinate of the second point`x`

= x coordinate of the first point_{1}

`y`

represents the unknown font size for a given viewport width `(x)`

. The coordinates `(x`

represent any given point on the line._{1}, y_{1})

Before we can use the point-slope form, we first need to compute what slope `m`

is. The formula to calculate slope `m`

(also known as the gradient of a line) is:

`m = (y`_{2} - y_{1}) / (x_{2} - x_{1})

Where:

`m`

= slope of the line formed by the two points `(x`_{1}, y_{1})

and `(x`_{2}, y_{2})

`(x`

= coordinates of the first point_{1}, y_{1})`(x`

= coordinates of the second point_{2}, y_{2})

We want our font size to be `32px`

when the viewport is `414px`

wide. So, let:

`x`

=_{1}`32px`

`y`

=_{1}`414px`

Thus, the coordinates of our first point are:

`(414, 32)`

We want our font size to be `48px`

when the viewport is `768px`

wide. So, let:

`x`

=_{2}`768px`

`y`

=_{2}`48px`

Thus, the coordinates of our second point are:

`(768, 48)`

Now, let's plug in the given values to the formula `m = (y`

to compute our slope:_{2} — y_{1}) / (x_{2} — x_{1})

`m = (48 - 32) / (768 - 414)`

`m = 16 / 354`

`m = 0.04519774011`

Now that we have the value of slope m, we can get back to our point-slope form:

`y - y`_{1} = m(x - x_{2})

Note that the coordinates `(x`

represent a point on the line with a slope _{1}, y_{1})`m = 0.04519774011`

(based on our previous calculations).

Using the formula `y — y`

, we can now solve for the unknown font size _{1} = m(x — x_{1})`(y)`

when viewport width `(x)`

is, for example, `591px`

(which is halfway between `414px`

and `768px`

; we can intuitively estimate that the unknown font size (y) should therefore be halfway between `32px`

and `48px`

):

`y - 32 = 0.04519774011 (591 - 414)`

`y - 32 = 0.04519774011 (177)`

`y - 32 = 7.9999999977`

`y = 7.9999999977 + 32`

`y = 39.9999999977`

As expected, font size `(y)`

is halfway between `32px`

and `48px`

.

Now, how do we use all this math in CSS to achieve fluid font size? This is where the CSS `calc()`

function comes in.

Let's update our example to use CSS's `calc()`

function :

```
:root {
/* Declare without units so we can compute the slope */
--min-vw: 414;
--max-vw: 768;
--min-h1-font-size: 32;
--max-h1-font-size: 48;
/* m = (y2 - y1) / (x2 - x1) */
--rise: calc(var(--max-h1-font-size) - var(--min-h1-font-size));
--run: calc(var(--max-vw) - var(--min-vw));
--slope: calc(var(--rise) / var(--run));
}
h1 {
/* Due to the way addition and subtraction works in calc(),
we need to "type cast" --min-vw and --min-h1-font-size to appropriate units */
--min-vw-px: calc(var(--min-vw) * 1px);
--min-h1-font-size-px: calc(var(--min-h1-font-size) * 1px);
/* y - y1 = m(x - x1) */
--fluid-font-size-px:
calc(
var(--slope) * (100vw - var(--min-vw-px)) + var(--min-h1-font-size-px)
);
font-size: var(--fluid-font-size-px);
}
```

The key to making fluid font size work in our example is the use of `100vw`

for the value of `x`

in the point-slope formula.

We have now achieved the precision control we were aiming for. When the viewport's width is `414px`

, the font size is `32px`

. When the viewport's width is `768px`

, the font size is `48px`

. Solving for any other viewport width `(x)`

and font size `(y)`

on the same line with a slope of `m = 0.04519774011`

, we can use the point-slope formula `y — 32 = 0.04519774011(x — 414)`

.

### Advanced Fluid Font Size

Another drawback of setting the font-size property to a vw unit is that this may result in extremely small or large font sizes. What if you wanted the font size to never go below `32px`

or above `48px`

?

In order to set boundaries for the font size, we need to use CSS's `clamp()`

function.

According to the MDN Web Docs,

the`clamp()`

CSS function clamps a value between an upper and lower bound.`clamp()`

enables selecting a middle value within a range of values between a defined minimum and maximum. [It] takes three comma separated expressions as its parameter, in the order of minimum value, preferred value, maximum value.

So, if we were to set the first parameter to `32px`

and the third parameter to `48px`

, we would have a font size that would never go below `32px`

or above `48px`

.

Let's update our example to use CSS's `clamp()`

function :

```
:root {
/* Declare without units so we can compute the slope */
--min-vw: 414;
--max-vw: 768;
--min-h1-font-size: 32;
--max-h1-font-size: 48;
/* m = (y2 - y1) / (x2 - x1) */
--rise: calc(var(--max-h1-font-size) - var(--min-h1-font-size));
--run: calc(var(--max-vw) - var(--min-vw));
--slope: calc(var(--rise) / var(--run));
}
h1 {
/* Due to the way addition and subtraction works in calc(),
we need to "type cast" --min-vw and --min-h1-font-size to appropriate units */
--min-vw-px: calc(var(--min-vw) * 1px);
--min-h1-font-size-px: calc(var(--min-h1-font-size) * 1px);
/* y - y1 = m(x - x1) */
--fluid-font-size-px:
calc(
var(--slope) * (100vw - var(--min-vw-px)) + var(--min-h1-font-size-px)
);
/* "Type cast" --max-vw to px */
--max-h1-font-size-px: calc(var(--max-h1-font-size) * 1px);
font-size:
clamp(
var(--min-h1-font-size-px),
var(--fluid-font-size-px),
var(--max-h1-font-size-px)
);
}
```

As you can see, when the viewport is `414px`

and below, the font size is `32px`

. And when the viewport is `768px`

and above, the font size is `48px`

. The font size is only fluid when the viewport's width is between `414px`

and `768px`

.

### Some Final Thoughts

- To keep the examples simple, I set the
`font-size`

property in px. This is not recommended by the Web Content Accessibility Guidelines (WCAG) . - Designers may argue that font size should be based on the element's container, not the viewport's width. Unfortunately, container relative lengths are not part of the CSS specification as of yet.
- Support for
`calc()`

and support for`clamp()`

are both fairly good. - You can also apply the same techniques for fluid font sizes to implement fluid line heights.

That depends on the devices your website needs to support and the aesthetics you wish to achieve.

Ideally, you would base your range on your website's statistics. Absent that, you can review a worldwide screen resolution statistics resource.

Pick a font size that is readable and accessible. For websites, regardless of device, the general consensus seems to be:

- Primary text should be
`16px`

- Secondary text should be about
`2px`

smaller than the primary text (so, about`13px`

or`14px`

) - Text input should be
*at least*`16px`

(so, about`18px`

)

As for headings, this is where you have the most flexibility to take advantage of fluid typography. Headings tend to be bigger than the primary text and therefore have the most room to resize.

For ideal readability, aim for a line height that is about 130% to 150% the size of the font (so, `1.3`

to `1.5`

). For optimal readability and accessibility, try 140% to 180% (that's `1.4`

to `1.8`

).

Smaller fonts require more line height, which is why you may want to specify a start line height that has a greater value than the end line height (assuming your font size is adjusting proportionally to the viewport's width).