Getting typography to look great on any screen is harder than it sounds. For years, web designers relied on media query breakpoints to resize text, but that method gets unwieldy fast as new devices and viewport sizes keep rolling out.

Starting with WordPress 6.1 (released in November 2022), there’s a cleaner approach: fluid typography. It smoothly scales the font sizes you define in your theme.json file so type adjusts gracefully, no matter the viewport’s width or height.

Beyond font size, the same technique can be applied to related properties—like line height and spacing—when you configure them to scale, giving you a more consistent, readable, and accessible experience across devices.

This article covers how fluid typography works, how it differs from breakpoint-based sizing, and how to set it up in WordPress using theme.json and CSS.

First, let’s revisit the old way of handling type, and why fluid sizing is such a meaningful upgrade.

Breakpoint typography vs. fluid typography

A helpful way to grasp fluid typography is to compare it to breakpoint-based typography, which depends on media queries that target specific viewport widths for font sizing.

Breakpoint typography

Breakpoints typically define ranges of viewport widths in pixels. A common pattern is three breakpoints aimed at mobile, laptop, and desktop screens.

Here’s a typical set of breakpoints for laptops in a CSS file:

@media (min-width: 48em) and (max-width: 74.9375em) {
  body {
    font-size: 1.125rem;
    line-height: 1.6;
  }
  h1 {
    font-size: 2rem;
  }
}

This works, but it doesn’t scale well: as more devices and screen sizes appear, maintaining a growing stack of queries becomes difficult and error-prone.

Illustrating how typography scales smoothly across breakpoints.
Illustrating how typography scales in discrete steps at breakpoints.

In the GIF above, as the viewport narrows, type changes size in noticeable jumps. This “stepping” can feel awkward and unpredictable—far from the smooth, continuous scaling most designs need.

Fluid typography

With the arrival of the CSS clamp() function in 2019 and viewport units (vw and vh), seamless, automatic scaling became practical.

These features let you define text that responds to the viewport’s dimensions, greatly reducing or eliminating the need for multiple breakpoints.

Here’s an example of a medium font size using clamp():

.has-medium-font-size {
  font-size: clamp(1rem, 1rem + 0.5vw, 1.25rem);
}

We’ll unpack clamp() shortly, but think of it as a formula with a minimum, a preferred (fluid) value, and a maximum. It keeps type within sensible bounds while scaling smoothly.

Demonstrating fluid typography.
Demonstrating fluid typography.

In this GIF, as the viewport gets smaller, the text resizes fluidly—no sudden jumps.

That continuous, natural scaling is the big advantage over breakpoint-only approaches. Rather than resizing in steps, your type adjusts at a steady pace across screens.

And smooth resizing is only part of the story. Fluid typography also makes it easier to build flexible, consistent, and accessible interfaces.

The case for fluid typography

As you put fluid typography to work, these benefits stand out.

Responsive by default

Text automatically scales with the viewport, so you can rely less on breakpoints. Whether someone visits on a phone, tablet, or ultra-wide monitor, sizes adapt without extra CSS.

Easier to maintain

Fewer media queries mean cleaner stylesheets. Define a simple “T-shirt” type scale—small through extra-large—and reuse it consistently across your theme.

Consistent design

Keep font sizes unified throughout your site, globally or per block as needed. Set the scale once and it propagates across blocks, patterns, and templates.

Improved accessibility and readability

Because sizes change smoothly, text remains comfortably readable on different devices and with user zoom—helpful for accessibility and overall legibility.

Future-proof design

Since type isn’t tied to fixed breakpoints, your scale continues to work as new screen sizes and devices come along.

Control over scaling speed

You can fine-tune how quickly text grows or shrinks by adjusting the preferred value (the middle term in clamp()) that responds to viewport width.

Browser support

The clamp() function is supported in all modern browsers, including current versions of Chrome, Edge, Firefox, and Safari.

For full coverage, include fallbacks for older browsers (for example, Internet Explorer 11 and some pre-2020 Safari and Chrome releases).

Here’s how to do that:

/* Fallback (for IE11 and other old browsers) */
li {
  font-size: 1.25rem; 
}

/* Preferred (modern browsers) */
li {
  font-size: clamp(1rem, 1rem + 0.5vw, 1.5rem);
}

How fluid typography works

Fluid typography relies on three values: a minimum, a maximum, and a preferred value that varies with viewport size. The preferred value tracks the viewport so the size transitions smoothly between the min and max.

The clamp() function expresses those values in a single rule:

font-size: clamp(min, preferred, max);

This guarantees text won’t get too small on compact screens or too large on wide displays. For example:

font-size: clamp(1rem, 1rem + 0.5vw, 1.25rem);

Here, the font starts at 1rem, scales up as the viewport expands, and stops growing at 1.25rem.

How WordPress handles it

WordPress takes care of the math. Instead of hand-calculating values, you define font sizes in theme.json.

Here’s a simplified example of how WordPress represents a font size in JSON:

{
  "fluid": {
    "min": "1rem",
    "max": "1.25rem"
  },
  "name": "Medium",
  "size": "1.125rem",
  "slug": "medium"
}

From that, WordPress generates the CSS for you:

font-size: clamp(1rem, 1rem + 0.5vw, 1.25rem);

This makes fluid type quick to implement and consistent across your theme. Set your values once in theme.json, and WordPress handles the rest.

Common terms

Before moving on, here are a few key units used with fluid typography. Each scales relative to a reference.

UnitDefinitionNotes
emRelative to the computed font size of the parent element.Sizes can compound through nesting.
remRelative to the root (html) element’s font size.Provides consistent scaling site-wide.
vw1% of the viewport width.Useful for width-based scaling.
vh1% of the viewport height.Useful for height-based scaling.

A few words about theme.json

theme.json is data-driven: you declare settings and styles, and WordPress outputs the CSS for you.

WordPress core ships with its own theme.json that establishes baseline values. A block theme’s theme.json builds on that, including how fluid typography is applied.

As with most style properties, you can override settings globally or per block—ideally in a child theme so updates are safe.

If you’re new to theme.json, we recommend reading “Working with properties and key-value pairs in theme.json.”

How WordPress uses fluid typography in TT5 (Twenty Twenty Five)

When a block theme’s theme.json includes "fluid": true, WordPress generates fluid typography using the CSS clamp() function. A built-in algorithm calculates values that scale smoothly between the minimum and maximum you provide.

{
  "settings": {
    "typography": {
      "fluid": true
    }
  }
}

If "fluid" is omitted, WordPress defaults to false, so sizes remain fixed rather than scaling fluidly.

With fluid typography enabled, TT5 defines five preset font sizes. Each includes minimum and maximum values that WordPress uses to generate the final CSS via clamp().

Size NameTheme.json valuesGenerated CSS clamp values
smallsize:0.875remclamp(0.875rem, 0.8125rem + 0.2vw, 1rem)
mediummin:1rem
max: 1.125rem
clamp(1rem, 0.9375rem + 0.25vw, 1.125rem)
largemin:1.125rem
max: 1.375rem
clamp(1.125rem, 1.0625rem + 0.5vw, 1.375rem)
x-largemin:1.75rem
max: 2rem
clamp(1.75rem, 1.5rem + 1vw, 2rem)
xx-largemin:2.15rem
max: 3rem
clamp(2.15rem, 1.9rem + 2vw, 3rem)

Practical examples

Now that we’ve seen how TT5 handles fluid type by default, let’s walk through a few real-world tweaks you might make.

For the following examples, we’ll use a TT5 child theme. As always, ensure your assets are enqueued correctly.

Increase all font sizes by 25%

If your audience benefits from larger text (for example, accessibility-focused or senior-friendly sites), you can scale up globally.

Option 1 — Using theme.json

There isn’t a single switch to scale everything at once, but you can raise each preset by 25%. Here’s one way to configure it:

"typography": {
  "fontSizes": [
    {
      "fluid": false,
      "name": "Small",
      "size": "1.09375rem",
      "slug": "small"
    },
    {
      "fluid": { "max": "1.40625rem", "min": "1.25rem" },
      "name": "Medium",
      "size": "1.25rem",
      "slug": "medium"
    },
    {
      "fluid": { "max": "1.71875rem", "min": "1.40625rem" },
      "name": "Large",
      "size": "1.725rem",
      "slug": "large"
    },
    {
      "fluid": { "max": "2.5rem", "min": "2.1875rem" },
      "name": "Extra Large",
      "size": "2.1875rem",
      "slug": "x-large"
    },
    {
      "fluid": { "max": "3.75rem", "min": "2.6875rem" },
      "name": "Extra Extra Large",
      "size": "2.6875rem",
      "slug": "xx-large"
    }
  ]
}

This follows TT5’s approach: the small size is fixed, while the larger sizes scale fluidly.

WordPress still calculates the preferred (fluid) values between each min and max for you.

Option 2 — Using style.css

Alternatively, bump everything up globally with one rule in your stylesheet:

:root {
  font-size: 125%;
}

This increases the root font size by 25%, which scales all elements that use rem units.

Custom fluid typeface for a single block

You can target fluid sizing to specific blocks when you need finer control.

For example, to set list items (core/list) to use the medium size instead of the default large, add this to your theme.json:

"styles": {
  "blocks": {
    "core/list": {
      "typography": {
        "fontSize": "var:preset|font-size|medium"
      }
    }
  }
}

The result is a clearer hierarchy, with list items slightly smaller than paragraphs.

single fluid typography block
Single fluid typography block.

Setting fluid typography in style.css

If you’re working with a classic theme, define your own clamp() values directly in style.css.

For example, here’s how to make list items 125% of the large font size:

li {
  font-size: clamp(1.725rem, 1.725rem + 0.17vw, 1.71875rem) !important;
}
fluid typography in WordPress
Using fluid typography.

This sets a larger size for list items via your CSS. If you’re using a classic theme, you’ll write the clamp() rule in your style.css file.

Fluid spacing

Type is only one piece of the puzzle when you adopt fluid systems.

Padding, margins, and block gaps (spacing inside group blocks) can also scale smoothly using the same principles as fluid type.

TT5 defines space sizes with the following settings.

"spacing": {
  "defaultSpacingSizes": false,
  "spacingSizes": [
    { "name": "Tiny", "size": "10px", "slug": "20" },
    { "name": "X-Small", "size": "20px", "slug": "30" },
    { "name": "Small", "size": "30px", "slug": "40" },
    { "name": "Regular", "size": "clamp(30px, 5vw, 50px)", "slug": "50" },
    { "name": "Large", "size": "clamp(30px, 7vw, 70px)", "slug": "60" },
    { "name": "X-Large", "size": "clamp(50px, 7vw, 90px)", "slug": "70" },
    { "name": "XX-Large", "size": "clamp(70px, 10vw, 140px)", "slug": "80" }
  ]
}

The first three sizes (tiny, x-small, small) are fixed; the larger steps scale fluidly with clamp().

This way, both your typography and layout spacing adapt elegantly across screen sizes.

Choosing sensible min and max values

A reliable way to pick your min and max sizes is to anchor them to two concrete layouts you actually design for—your narrowest comfortable reading width and your widest content width. Set the minimum for your smallest body size at the narrow width, then choose a maximum that preserves readable line length at the wide width.

  1. Pick a viewport range you care about (for example, 360px to 1280px).
  2. Decide a base text size that reads well at 360px (for example, 16px or 1rem).
  3. Find the largest base size that still yields 60–75 characters per line at 1280px (often 18–20px).
  4. Use those two values as the ends of your clamp.
/* Example: clamp base body text between 1rem and 1.125rem */
:root {
  --fs-body: clamp(1rem, 0.95rem + 0.5vw, 1.125rem);
}
body { font-size: var(--fs-body); }

Tip: heading scales should grow faster than body text. A common approach is to use larger slopes (the “vw” portion) as you go up the hierarchy.

Deriving clamp() by hand (the quick math)

You can compute the middle term yourself if you want consistent logic across your scale.

  1. Choose your min and max viewport widths (e.g., 360px and 1280px).
  2. Choose min and max font sizes (e.g., 16px and 20px).
  3. Compute the slope: (maxSize - minSize) / (maxVW - minVW).
  4. Convert slope to vw: multiply by 100 to get “per 100% width”.
  5. Compute the intercept: minSize - slope * minVW.
/* With minVW=360, maxVW=1280, minSize=16px, maxSize=20px */
:root {
  --fs-body: clamp(1rem, 0.875rem + 0.625vw, 1.25rem);
}

Don’t worry about being perfect—pick readable endpoints first, then iterate if the rate of growth feels too fast or slow.

Fluid line-height, measure, and rhythm

Scaling font-size is only half the story. You’ll get better results if line-height, line length (measure), and vertical spacing adapt too.

  • Line-height: keep it slightly higher at small sizes and tighten a bit as sizes grow.
  • Measure: aim for 60–75 characters per line for body text. The ch unit is perfect for this.
  • Rhythm: tie margins and gaps to a fluid space scale so blocks breathe consistently.
/* Fluid line-height that eases from 1.6 to 1.45 across the range */
:root {
  --lh-body: clamp(1.45, 1.3 + 0.5vw, 1.6);
}
p { line-height: var(--lh-body); }

/* Constrain readable measure */
p, li {
  max-inline-size: clamp(55ch, 50ch + 5vw, 75ch);
}

/* Fluid block spacing (vertical rhythm) */
:root {
  --space-1:  clamp(0.5rem, 0.4rem + 0.4vw, 0.75rem);
  --space-2:  clamp(0.75rem, 0.6rem + 0.8vw, 1.25rem);
  --space-3:  clamp(1rem, 0.8rem + 1.2vw, 2rem);
}
p + p { margin-block-start: var(--space-2); }

Component-level scaling with container queries

Viewport-based scaling is great, but sometimes a component lives in a narrow sidebar on a large screen. Container queries let type scale with the component’s own width rather than the whole viewport.

/* 1) Make a component a size container */
.card {
  container-type: inline-size; /* establishes a container */
  padding: var(--space-2);
}

/* 2) Scale heading inside the card by the card's width */
.card h3 {
  font-size: clamp(1rem, 0.9rem + 2cqw, 1.5rem); /* cqw = 1% of container width */
}

/* 3) Use @container for step adjustments if needed */
@container (min-width: 40rem) {
  .card h3 { letter-spacing: -0.005em; }
}

Use container-based scaling for cards, sidebars, and widgets; keep viewport-based scaling for document-level elements like body text and page titles.

WordPress: advanced theme.json tips

  • Expose tokens as CSS variables: WordPress generates --wp--preset--font-size--* variables for your presets. Reference them directly in custom CSS to keep everything in sync.
/* Use theme presets in custom CSS */
.entry-content { font-size: var(--wp--preset--font-size--medium); }
.entry-content h2 { font-size: var(--wp--preset--font-size--x-large); }
  • Per-block overrides: In theme.json, use the styles.blocks section to assign a different preset (or entirely custom clamp) to specific blocks without touching global defaults.
{
  "styles": {
    "blocks": {
      "core/heading": {
        "typography": {
          "fontSize": "var(--wp--preset--font-size--x-large)",
          "lineHeight": "clamp(1.15, 1.1 + 0.3vw, 1.3)"
        }
      }
    }
  }
}
  • Editor parity: After defining presets, confirm that the Site Editor’s Typography panel offers the same names and behavior; rely on presets so authors can pick sizes without custom CSS.

Accessibility guardrails

  • Respect user scaling: Base sizes in rem so browser zoom and OS text-size preferences scale everything predictably.
  • Contrast and weight: If you reduce line-height at larger sizes, ensure color contrast and weight remain accessible. Avoid ultra-light weights for body copy.
  • Motion and transitions: Avoid animating font-size; it can be disorienting. Prefer instant changes.
  • Long words and wrapping: Prevent overflow in narrow layouts and languages with long compounds.
/* Wrapping and hyphenation helpers */
p, h1, h2, h3, h4 {
  overflow-wrap: anywhere;
  hyphens: auto;
}

Common pitfalls and how to fix them

  • Over-aggressive growth: If headings balloon too fast, reduce the vw portion of the clamp or lower the max size.
  • Cramped small screens: Increase the minimum size’s line-height and reduce letter-spacing slightly for headings to preserve clarity.
  • Inconsistent spacing: Tie margins and gaps to a shared fluid space scale instead of hard-coded rem values.
  • CLS from web fonts: Use font-display: swap and consider font-size-adjust to match fallback x-height and minimize layout shift.
@font-face {
  font-family: "Inter Var";
  src: url("/fonts/inter-var.woff2") format("woff2");
  font-display: swap;
  font-weight: 100 900;
  font-style: normal;
  font-size-adjust: 0.52; /* helps align fallback/loaded metrics */
}

A reusable fluid type scale with CSS variables

Define a small set of tokens and reuse them anywhere—classic or block themes.

:root {
  /* body base */
  --fs-0: clamp(1rem, 0.95rem + 0.5vw, 1.125rem);

  /* headings grow progressively faster */
  --fs-1: clamp(1.125rem, 1rem + 1vw, 1.375rem);
  --fs-2: clamp(1.375rem, 1.15rem + 1.6vw, 1.75rem);
  --fs-3: clamp(1.75rem, 1.4rem + 2.4vw, 2.5rem);
  --fs-4: clamp(2.25rem, 1.7rem + 3.4vw, 3.25rem);
}

body { font-size: var(--fs-0); }
h6 { font-size: var(--fs-1); line-height: 1.3; }
h5 { font-size: var(--fs-2); line-height: 1.25; }
h4 { font-size: var(--fs-2); line-height: 1.25; }
h3 { font-size: var(--fs-3); line-height: 1.2;  }
h2 { font-size: var(--fs-3); line-height: 1.15; }
h1 { font-size: var(--fs-4); line-height: 1.1;  }

Testing checklist

  • Zoom to 200% and 400% and confirm the layout remains usable and readable.
  • Resize the viewport from phone widths to large monitors; watch for awkward leaps or crowded lines.
  • Toggle between system fonts and your web font to ensure line length still feels right with fallbacks.
  • Check languages with longer words (e.g., German, Finnish) and CJK scripts; adjust measure and wrapping as needed.
  • Review in the WordPress editor (list view + canvas) to ensure presets feel consistent for authors.

Migration playbook (from breakpoint steps to fluid)

  1. Inventory existing font sizes and where they change at breakpoints.
  2. Pick a min and max viewport and derive clamp values for your base and headings.
  3. Replace stepped media queries with clamp-based tokens; keep only a few targeted breakpoints for exceptions.
  4. Unify spacing with a small fluid space scale to stabilize rhythm.
  5. Validate accessibility at common zoom levels; ship, then iterate on the slope if growth feels off.

Summary

Breakpoint-based and fluid typography serve different roles. Used together, they produce resilient layouts that scale smoothly and deliver consistent, readable experiences for everyone.

If you’d rather not calculate values by hand, these free tools make it easy to fine-tune and preview your scale:

These helpers generate clamp() values that match your design system—especially handy when you’re working with classic themes.

Ready to try it in production? Choose a performant WordPress host with fast TTFB, a global CDN, and edge caching so your fluid type renders quickly and consistently everywhere.

  • Scaling typeface gracefully with fluid typography CSS

    Scaling typeface gracefully with fluid typography CSS

    Getting typography to look great on any screen is harder than it sounds. For years, web designers relied on media query breakpoints to resize text, but that method gets unwieldy fast as new devices and viewport sizes keep rolling out. Starting with WordPress 6.1 (released in November 2022), there’s a cleaner approach: fluid typography. It…

  • WordPress 6.9: What’s New (And What You Should Try First)

    WordPress 6.9: What’s New (And What You Should Try First)

    WordPress 6.9 is set for release soon, bringing a host of new features and refinements to the world’s leading content management system. This update marks another step forward in delivering a more powerful, flexible, and intuitive platform for both users and developers. Here’s a quick summary of the major improvements you can expect in WordPress…