Fluid Responsive Typography With CSS Poly Fluid Sizing

Quick Summary

Fluid layouts have been a normal part of front-end development for years. The idea of fluid typography, however, is relatively new and has yet to be fully explored. Up until now, most developers’ idea of fluid typography is simply using Viewport units maybe with some minimum and maximum sizes.
In this article, we are going to take it to another level. We are going to examine how to create scalable, fluid typography across multiple breakpoints and predefined font sizes using well-supported browser features and some basic algebra. The best part is that you can automate it all by using Sass.

Table of Contents

Members support Smashing

Wonderful, friendly people who keep this lil' site alive — and get smarter every day.

Fluid layouts have been a normal part of front-end development for years. The idea of fluid typography, however, is relatively new and has yet to be fully explored. Up until now, most developers’ idea of fluid typography is simply using Viewport units maybe with some minimum and maximum sizes.

In this article, we are going to take it to another level. We are going to examine how to create scalable, fluid typography across multiple breakpoints and predefined font sizes using well-supported browser features and some basic algebra. The best part is that you can automate it all by using Sass.

When working with creative designers on web page designs, it’s fairly common to receive multiple Sketch or Photoshop artboards/layouts, one for each breakpoint. In that design, elements (like an h1 heading) will usually be different sizes at each breakpoint. For example:

“You must unlearn what you have learned!” Meet the brand new episode of SmashingConf San Francisco with smart front-end tricks and UX techniques. Featuring Yiying Lu, Aarron Draplin, Smashing Yoda, and many others. Tickets now on sale. April 17-18.

This is a good first step, but you are limiting the font-size to only what was specified by the designer at the provided breakpoints. What would the designer say if you asked, “What should the font-size be at an 850px wide viewport?” The answer in most cases is that it would be somewhere between 24px and 34px. But right now, it’s just 24px according to your CSS, which is probably not what the designer was envisioning.

Your option at this point is to calculate what that size should be and add another breakpoint. That’s easy enough. But what about all the other resolutions? What should the font-size be at 800px wide? What about 900px? What about 935px? Obviously the designer is not going to provide you with a full layout for every single possible resolution. Even if they did, should you be adding dozens (or hundreds) of breakpoints for all the different font-sizes that are desired by the designer? Of course not.

Your layout is already fluidly scaling with the width of your viewport. Wouldn’t it be nice if your typography predictably scaled with your fluid layout? What else can we do to improve upon this?

Viewport Units To The Rescue?

Viewport units are another step in the right direction. They allow your text to fluidly resize with your layouts. And the browser support is great these days.

But the viability of Viewport units is very dependent on the original creative designs for a web page. It would be great to just set your font-size using vw and be done:

h1 {
font-size: 2vw;
}

But this only works if your creative art-boards take this into account. Did the designer choose a text size that was exactly 2% of the width of each of his art-boards? Of course not. Let’s calculate what the vw value would need to be for each of our breakpoints:

They are close but they aren’t all the same. So you would still need to use media queries to transition between text sizes and there would still be jumps. And consider this weird side-effect:

@ 767px, 3.82% of the viewport width is 29px. If the viewport is 1-pixel wider the font-size sudden drops back down to 24px. This animation of a viewport being resized demonstrates this undesirable side effect:

This dramatic change in font-size is almost definitely not what the designer was envisioning. So how do we solve this problem?

Statistical Linear Regression?

Wait. What? Yes, this is an article about CSS, but some basic math can go a long way towards an elegant solution to our problem.

Here you can see a scatter plot of the designer’s specified text sizes at the defined viewport widths. The x-axis is the viewport width and the y-axis is the font-size. See that line? That’s called a trendline. It’s a way to find an interpolated font-size value for any viewport width, based on the data provided.

The Trendline Is The Key To All Of This

If you could set your font-size according to this trendline, you would have an h1 that smoothly scales on all resolutions that would come close to matching what the designer intended. First, let’s look at the math. The straight line is defined by this equation:

Linear equation definition

m = slope

b = the y-intercept

x = the current viewport width

y = the resulting font-size

The are several methods for determining the slope and y-intercept. When multiple values are involved, a common method is the Least Squares fit:

Once you run those calculations, you have your trendline equation.

Is your pattern library up to date today? Alla Kholmatova has just finished a fully fledged book on Design Systems and how to get them right. With common traps, gotchas and the lessons she learned. Hardcover, eBook. Just sayin'.

How Do I Use This In CSS?

Okay, this is getting pretty heavy on the math. How do we actually use this stuff in front-end web development? The answer is CSS calc()! Once again, a fairly new CSS technology that is very well supported.

Does this really work? Open up this CodePen and resize your browser window. It works! The font sizes are fairly close to what the original design was asking for and they smoothly scale with your layout.

Now, admittedly, it’s not perfect. The values are close to the original design but they do not quite match up. This is because a linear trendline is an approximation of specific font sizes at specific viewport widths. This is inherit of linear regression. There is always some error in your results. It’s a trade-off of simplicity vs. accuracy. Also, keep in mind, the more varied your text sizes are, the more error there will be in your trendline.

Can we do better than this?

Polynomial Least Squares Fit

In order to get a more accurate trendline, you need to look at more advanced topics, like a polynomial regression trendline that might look something like this:

Now that is more like it! Much more accurate than our straight line. A basic polynomial regression equation looks like this:

A 3rd degree polynomial equation

The more accurate you want your curve, the more complicated the equation gets. Unfortunately, you can’t do this in CSS. calc() simply cannot do this type of advanced math. Specifically, you can’t calculate exponents:

font-size: calc(3vw * 3vw); /* This doesn’t work in CSS */

So until calc() supports this type of non-linear math, we are stuck with linear equations only. Is there anything else we can do to improve upon this?

Breakpoints And Multiple Linear Equations

What if we were only calculating a straight line between each pair of breakpoints? Something like this:

The poly-fluid-sizing() mixin will perform linear interpolation on each pair of viewport widths and set a minimum and maximum size. You can import this into any Sass project and easily utilize it without needing to know any of the math behind it. Here is the final CodePen that uses this method.

A Few Notes

Obviously this method applies not only to font-size but to any unit/length property (margin, padding, etc). You pass the desired property name into the mixin as a string.

The Sass map of viewport width + size value pairs can be passed in any order into the poly-fluid-sizing() mixin. It will automatically sort the map according to Viewport width from lowest to highest. So you could pass in a map like this and it would work out just fine:

A limitation for this method is that you cannot pass in mixed units into the mixin. For example, 3em @ 576px width. Sass just won’t really know what to do mathematically there.

Conclusion

Is this the best we can do? Is Poly Fluid Sizing the Holy Grail of fluid unit sizing in CSS? Maybe. CSS currently supports non-linear animation and transition timing functions, so maybe there is a chance that calc() will also support it someday. If that happens, non-linear, polynomial regression might be worth a look again. But maybe not… Linear scaling might be superior anyways.

I began exploring this idea in early 2017 and eventually developed the above solution. Since then, I’ve seen a few dev’s come up with similar ideas and different pieces of this puzzle. I thought it was time for me to share my method and how I got there. Viewport units. Calc(). Sass. Breakpoints. None of these things are new. They are all browser features that have existing for years (with varying degrees of support). I’ve only used them together in a way that hadn’t been fully explored yet. Don’t ever be afraid to look at the tools you use every day and think out-of-the-box on how you can utilize them better and grow your skill set.