Choose Theme

Responsive Fluid Typography with Tailwind

· 3 min read · #CSS #Tailwind
--

Create smooth, responsive text that scales perfectly between breakpoints using CSS clamp().

CSS utility:

src/styles/typography.css
.text-fluid-sm {
font-size: clamp(0.875rem, 0.8rem + 0.5vw, 1rem);
/* Min: 14px, Preferred: scales with viewport, Max: 16px */
}
.text-fluid-base {
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
/* Min: 16px, Preferred: scales, Max: 18px */
}
.text-fluid-lg {
font-size: clamp(1.125rem, 1rem + 0.75vw, 1.5rem);
/* Min: 18px, Max: 24px */
}
.text-fluid-xl {
font-size: clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem);
/* Min: 24px, Max: 36px */
}
.text-fluid-2xl {
font-size: clamp(2rem, 1.5rem + 2.5vw, 3rem);
/* Min: 32px, Max: 48px */
}
.text-fluid-3xl {
font-size: clamp(2.5rem, 2rem + 3vw, 4rem);
/* Min: 40px, Max: 64px */
}

Tailwind plugin:

tailwind.config.mjs
import plugin from 'tailwindcss/plugin';
export default {
// ... your config
plugins: [
plugin(function ({ addUtilities }) {
addUtilities({
'.text-fluid-sm': {
'font-size': 'clamp(0.875rem, 0.8rem + 0.5vw, 1rem)',
},
'.text-fluid-base': {
'font-size': 'clamp(1rem, 0.9rem + 0.5vw, 1.125rem)',
},
'.text-fluid-lg': {
'font-size': 'clamp(1.125rem, 1rem + 0.75vw, 1.5rem)',
},
'.text-fluid-xl': {
'font-size': 'clamp(1.5rem, 1.2rem + 1.5vw, 2.25rem)',
},
'.text-fluid-2xl': {
'font-size': 'clamp(2rem, 1.5rem + 2.5vw, 3rem)',
},
'.text-fluid-3xl': {
'font-size': 'clamp(2.5rem, 2rem + 3vw, 4rem)',
},
});
}),
],
};

Usage:

<!-- Old way: Multiple breakpoints -->
<h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl">
Heading
</h1>
<!-- New way: One class, smooth scaling -->
<h1 class="text-fluid-3xl">
Heading
</h1>
<!-- Paragraph text -->
<p class="text-fluid-base">
This text smoothly scales from 16px to 18px based on viewport width.
</p>

Visual comparison:

Old approach (breakpoints):
320px: 16px ─┐
640px: 16px │ Jump!
641px: 18px ─┘
1024px: 18px
New approach (fluid):
320px: 16.0px
480px: 16.8px ← Smooth
640px: 17.6px ← Smooth
1024px: 18.0px

Calculate clamp values:

function fluidType(minSize, maxSize, minWidth = 320, maxWidth = 1280) {
const minSizeRem = minSize / 16;
const maxSizeRem = maxSize / 16;
const slope = (maxSize - minSize) / (maxWidth - minWidth);
const yAxisIntersection = -minWidth * slope + minSize;
const yAxisIntersectionRem = yAxisIntersection / 16;
const slopeVw = slope * 100;
return `clamp(${minSizeRem}rem, ${yAxisIntersectionRem.toFixed(2)}rem + ${slopeVw.toFixed(2)}vw, ${maxSizeRem}rem)`;
}
console.log(fluidType(16, 24, 320, 1280));
// Output: clamp(1rem, 0.67rem + 0.83vw, 1.5rem)

Advanced: Fluid line height

.prose-fluid {
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
line-height: clamp(1.5rem, 1.4rem + 0.75vw, 1.75rem);
/* Line height scales proportionally */
}

Accessibility note:

/* Respect user's font size preferences */
html {
font-size: 100%; /* Don't override! */
}
/* clamp() respects user zoom and font size settings ✅ */
.text-fluid-base {
font-size: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
}

When to use:

  • Headings that need to scale smoothly
  • Hero text on landing pages
  • Paragraph text for better readability
  • Any text that looks awkward with breakpoint jumps

When NOT to use:

  • UI elements with fixed sizes (buttons, badges)
  • Small text where precision matters
  • When you need exact sizes at breakpoints

Related