---
title: "TailwindCSS: Fluid typography with CSS Clamp"
date: "5/7/2021, 9:51 PM"
category: "Development"
topics: ["tailwind", "tailwindcss", "css", "utility-first"]
canonical: "https://sveltekit.davidhellmann.com/blog/tailwindcss-fluid-typography-with-css-clamp"
section: "blog"
---

# TailwindCSS: Fluid typography with CSS Clamp

![Tailwindcss font size clamp](https://static.davidhellmann.com/assets/com_davidhellmann/images/blog/tailwindcss-font-size-clamp.png)

<p>Wait, a <a href="https://tailwindcss.com/">Tailwind CSS</a> article? Of course, I just had to jump on the hype train. But seriously. I was skeptical for a long time and still am partly. But after a few weeks, I've been playing around with it a bit more, and I plan to use it more intensively in the future. But that should not be the topic now so quickly back to the headline: Fluid Typography with CSS Clamp.</p><p>One point that bothers me about TailwindCSS is how to handle font sizes. In sum, there are just too many jumps that I have to remember, and that a team has to remember. Here, you quickly get a problem with consistency. Is the breakpoint set? Is the breakpoint correct? Are the sizes right? There are many sources of error.</p><p>Fortunately, there are ways to simplify the whole thing significantly. Since IE11 support is becoming a less and less common requirement for projects, you can use CSS features like <a href="https://caniuse.com/css-math-functions">Clamp (Can I use)</a>, a pretty powerful CSS property that fits perfectly for this purpose.</p>

**It looks like this**

```css
/* CSS Clamp */
/* clamp(MIN_VALUE, FLUID_VALUE, MAX_VALUE) */

.sample {
  font-size: clamp(18px, 2vw, 24px); 
}
```

<p>Integrating the whole thing into Tailwind CSS is a bit more complicated. The <strong>FLUID_VALUE</strong> calculation is a more complex calculation that requires more values from the TailwindCSS config. Let's have a look at the whole thing in detail.</p>

**tailwind.settings.js**

```javascript
/*
 * Tailwind Settings
 */

module.exports = {
  typography: {
    fontSizeMin: 1.125,
    fontSizeMax: 1.25,
    msFactorMin: 1.125,
    msFactorMax: 1.2,
    lineHeight: 1.6,
  },
  screensRem: {
    min: 20,
    sm: 40,
    md: 48,
    lg: 64,
    xl: 80,
    '2xl': 96,
  },
  grid: {
    cols: 24,
  },
}
```

<p>This is a part of my Tailwind CSS Config, where I store some global stuff. In our case the typography and screens stuff is relevant.</p>

**tailwind.settings.screens.js**

```javascript
/*
 * Tailwind Screens Settings
 */

const settings = require('./tailwind.settings')

const remToPx = (rem) => {
  return `${rem * 16}px`
}

module.exports = {
  sm: remToPx(settings.screensRem.sm),
  md: remToPx(settings.screensRem.md),
  lg: remToPx(settings.screensRem.lg),
  xl: remToPx(settings.screensRem.xl),
  '2xl': remToPx(settings.screensRem['2xl']),
}
```

<p>Here I get my breakpoint values from the <strong>tailwind.settings.js</strong> file, which are stored there, without unit, as REM values and then convert them to pixels, since I use the breakpoints within TailwindCSS with pixel values.</p>

**tailwind.settings.fontSizes.js**

```javascript
/*
 * Tailwind Font Size Settings
 */

const settings = require('./tailwind.settings')
const fsMin = settings.typography.fontSizeMin
const fsMax = settings.typography.fontSizeMax
const msFactorMin = settings.typography.msFactorMin
const msFactorMax = settings.typography.msFactorMax
const screenMin = settings.screensRem.min
const screenMax = settings.screensRem['2xl']

// Calc Min and Max Fontsize
const calcMulti = (multiMin = 0, multiMax = null) => {
  return {
    fsMin: fsMin * Math.pow(msFactorMin, multiMin),
    fsMax: fsMax * Math.pow(msFactorMax, multiMax || multiMin),
  }
}

// build the clamp property
const clamp = (multiMin = 0, multiMax = null) => {
  const _calcMulti = calcMulti(multiMin, multiMax || multiMin)
  const _fsMin = _calcMulti.fsMin
  const _fsMax = _calcMulti.fsMax
  return `clamp(${_fsMin}rem, calc(${_fsMin}rem + (${_fsMax} - ${_fsMin}) * ((100vw - ${screenMin}rem) / (${screenMax} - ${screenMin}))), ${_fsMax}rem)`
}

module.exports = {
  xs: clamp(-2),
  sm: clamp(-1),
  base: clamp(0),
  lg: clamp(1),
  xl: clamp(2),
  '2xl': clamp(3),
  '3xl': clamp(4),
  '4xl': clamp(5),
  '5xl': clamp(6),
  '6xl': clamp(7),
  '7xl': clamp(8),
  '8xl': clamp(9),
  '9xl': clamp(10),
}
```

<p>Let's move on to the most exciting config file. In <strong>the tailwind.settings.fontSizes.js</strong> file, we assemble our clamp property. First, we get some settings from <strong>tailwind.config.js,</strong> and then there are two helper functions.</p><p>One is <strong>calcMulti, where we simply calculate the minimum and maximum font sizes</strong> depending on our multiplier. The whole thing happens without units and in REM.</p><p>The second helper function <strong>clamp</strong> assembles our clamp property. Details about this calculation can be found here: <a href="https://websemantics.uk/tools/responsive-font-calculator/">Fluid-responsive font-size calculator,</a> where everything is explained quite well.</p>

**tailwind.config.js**

```javascript
/*
 * TailwindCSS Config
 * */

// Settings
const settingsScreens = require('./tailwind.settings.screens')
const settingsFontSizes = require('./tailwind.settings.fontSizes')


module.exports = {
  ...
  theme: {
    ...
    screens: settingsScreens,
    fontSize: settingsFontSizes,
    ...
  },
}
```

<p>Our tailwind.config.js then looks like this (shortened version).</p><h2>Final output</h2><p>If we look at the whole thing in the DEV tools in the browser, we see the following line of code for our body font (.<strong>text-base</strong>). This means nothing else than that our body font has a <strong>minimum value of: 1.125rem (18px)</strong> and a <strong>maximum value of 1.25rem (20px)</strong>. Everything in between is fluid. The minimum value in our example <strong>starts at 20rem (320px),</strong> and the maximum value is <strong>reached at 96rem (1536px)</strong>. That means the middle value controls everything in between. No more breakpoints are needed. Love it!</p><p>The example <strong>.text-5xl</strong> shows the whole thing with the multiplier 6. In this case, this is my <strong>H1</strong>.</p>

**typography.css**

```css
.text-base {
  font-size: clamp(1.125rem, calc(1.125rem + (1.25 - 1.125) * ((100vw - 20rem) / (96 - 20))), 1.25rem);
}

.text-5xl {
  font-size: clamp(2.2806973457336426rem, calc(2.2806973457336426rem + (3.732479999999999 - 2.2806973457336426) * ((100vw - 20rem) / (96 - 20))), 3.732479999999999rem);
}
```
