Index

Fluid Design with CSS Round

I feel a little conflicted about fluid type/spacing. I love how it simplifies CSS and enables truly responsive design. I always dig a massive, unapologetic heading that elegantly scales with the viewport. And, I’ve worked a lot with Utopia over the last few years — it rocks.

But, I also like working to a baseline grid. The two don’t always pair well.

Fluid design encourages us to define a minimum/maximum value and interpolate between the two based on a container size. We define the parameters and let the browser make the final decision. Until now, it has been impossible to ensure the browser chooses values that align to a baseline grid.

The CSS round() function changes that.


A practical example

The design team we are working with handles both product and marketing design. They use a 4px baseline grid to ensure consistency across the board.

We are building out a new page that includes a hero with an important piece of introductory text. This text should be around 32px on larger viewports, and scale down to around 16px on smaller viewports.

Typography

We decide to use clamp() alongside a unitless line-height value to ensure the heading automatically scales.

.hero {
  --heading-font-size: clamp(1rem, 2vw, 2rem);
  --heading-line-height: 1.25;
}

.hero h1 {
  font-size: var(--heading-font-size);
  line-height: var(--heading-line-height);
}

In doing so, we immediately break the vertical rhythm of the page.

As the heading resizes, and it’s fluid font-size is multiplied by it’s line-height, it’s total height is no longer a multiple of 4.

Three pieces of text sat side by side. The text increases in size across the canvas. Three pieces of text sat side by side. The text increases in size across the canvas.

Here’s where round() comes in.

Browser support for round() is somewhat limited. It’s worth providing a fallback.

.hero {
  /* “4px” grid */
  --grid-size: 0.25rem;

  --heading-font-size: clamp(1rem, 2vw, 2rem);
  --heading-line-height: round(
    var(--heading-font-size) * 1.25,
    var(--grid-size)
  );
}

.hero h1 {
  font-size: var(--heading-font-size);
  line-height: var(--heading-line-height);
}

Thanks to the code above, the line-height value is always a multiple of 4px, and the heading is aligned with the baseline grid.

Three pieces of text sat side by side. The text increases in size across the canvas. Three pieces of text sat side by side. The text increases in size across the canvas.

Spacing

This same technique can be applied to the spacing values of the hero.

.hero {
  padding: round(clamp(1rem, 10vw, 4rem), var(--grid-size));
}

Demo

Is it worth it?

Baseline grids lend an intangible harmony and “sturdiness” that can be hard to achieve otherwise. A great example of this is Tailwind — it’s type and spacing system subtly encourages a 4px grid, subconsciously making everything feel just right.

This round() and clamp() technique works with the browser rather than against it, and is definitely worth experimenting with.