# CSS clamp() for Fluid Typography Explained

###### Use CSS clamp() for fluid typography that scales smoothly without media queries. Learn the safer rem + vw pattern, cqi variant, and common gotchas.

You can make text responsive without media queries by using `clamp()` for the font size.

```css
font-size: clamp(24px, 10vw, 48px);
```

This gives the browser a minimum size, a fluid middle value, and a maximum size. The text scales smoothly instead of jumping at each breakpoint.

## Why media queries feel rough for type

A text size scale that uses breakpoints may look like this:

```css
h1 {
  font-size: 24px;
}

@media (min-width: 480px) {
  h1 {
    font-size: 32px;
  }
}

@media (min-width: 768px) {
  h1 {
    font-size: 40px;
  }
}

@media (min-width: 1200px) {
  h1 {
    font-size: 48px;
  }
}
```

This works, but the text jumps from one size to the next.

When you slowly change the browser width, the heading jumps at each breakpoint. It does not grow or shrink in a smooth way. You also have more CSS to care for, and each new breakpoint adds one more number that you may need to change later.

## How `clamp()` works

`clamp()` accepts three values:

```css
font-size: clamp(MINIMUM, PREFERRED, MAXIMUM);
```

For `clamp(24px, 10vw, 48px)`, each value does a different job:

*   `24px` is the smallest size. The text cannot get smaller than this.
    
*   `10vw` makes the text grow and shrink. One `vw` is 1% of the viewport width, so the value changes when the screen width changes.
    
*   `48px` is the largest size. The text cannot get bigger than this.
    

Between the smallest and largest sizes, the browser uses `10vw`. Below that range, it uses `24px`. Above it, the browser uses `48px`. One line replaces the media query block, and the text changes size in a smooth way.

![](https://storage.webdevvisuals.com/thumbnails/css-fluid-typography-444be.png%22 align="center")

<iframe src="https://storage.webdevvisuals.com/visuals/css-fluid-typography-444be.mp4" style="display:block;width:100%;height:500px;margin:2rem 0;border:0;border-radius:1rem"></iframe>

One detail matters here. `10vw` reaches `24px` when the viewport is `240px` wide. It reaches `48px` when the viewport is `480px` wide. On wider screens, the heading stays at its largest size. This works well when the text should grow only on small screens. If the heading should keep growing on tablets and desktops, use a smaller middle value.

## A safer middle value: `rem + vw`

Using only viewport units can make text harder to read. These units do not follow the reader's browser text size. If someone increases their default text size, a middle value that only uses `vw` can work against that choice.

Mix `rem` into the middle value instead:

```css
font-size: clamp(1rem, 0.5rem + 2vw, 1.5rem);
```

The `rem` part follows the main text size, while `2vw` makes the text grow with the screen. This is usually a better production choice than a middle value that only uses viewport units.

Test it at 200% zoom too. Even a good formula can make text wrap in a bad place inside a small card, or it can push nearby buttons off the screen.

## How to tell when `clamp()` stops scaling

To see where a value stops being fluid, set the middle value equal to the minimum and maximum.

*   `10vw = 24px` means the scaling starts at `240px`.
    
*   `10vw = 48px` means the scaling stops at `480px`.
    

That quick check helps you choose a better middle value. If the value reaches its maximum too early on desktop, lower the `vw` part and add more `rem`.

## Scale against a container with `cqi`

`clamp()` does not have to use the screen width. A unit such as `cqi` lets a value use the width of its parent box:

```css
.card {
  container-type: inline-size;
}

.card h2 {
  font-size: clamp(1rem, 0.5rem + 4cqi, 2rem);
}
```

Here, `1cqi` is 1% of the card's width. The heading now changes with the card instead of the screen. The same card can sit in a small side area or a wide top area without a new class. This is one of the cleanest upgrades once a value really belongs to a component instead of the full page.

## Notes

If the smallest value is bigger than the largest value, the smallest value wins. The browser does not warn you, so check the numbers if a value seems stuck.

Most new browsers support `clamp()`. If you need to support an old browser, put a fixed value first:

```css
h1 {
  font-size: 2rem;
  font-size: clamp(1.5rem, 1rem + 2.5vw, 3rem);
}
```

Browsers that do not know `clamp()` skip the second line and keep `2rem`.

`clamp()` works with media queries. It does not replace them. Use it for values that should grow and shrink, such as text sizes, space, gaps, and widths.

## Related patterns

For layouts rather than text, [`auto-fit` and `minmax()` can build a responsive CSS grid without media queries](https://www.webdevvisuals.com/blog/css-responsive-grid-without-media-queries).

If cards should wrap as rows instead of staying on grid tracks, [responsive Flexbox cards use `flex-grow` and `flex-basis`](https://www.webdevvisuals.com/blog/responsive-flexbox-cards-without-media-queries).

If the problem is keeping media boxes in shape, [CSS `aspect-ratio` handles responsive images and videos](https://www.webdevvisuals.com/blog/css-aspect-ratio-without-media-queries).

For a single element that should shrink and stop growing, use [`width` with `max-width` for responsive CSS widths](https://www.webdevvisuals.com/blog/css-responsive-widths-without-media-queries).

You can also read the full guide to [responsive CSS without media queries](https://www.webdevvisuals.com/blog/responsive-css-without-media-queries).

You can browse more [frontend visuals and CSS examples](https://www.webdevvisuals.com/explore).

## Wrap-up

`clamp()` replaces many font-size breakpoint rules with one readable line. Use a `rem + vw` middle value, test at 200% zoom, and switch to `cqi` when the value should follow a container instead of the viewport.

You can browse more short frontend tips & tricks on [WebDevVisuals](https://www.webdevvisuals.com).
