Fluid typography is the idea that font-size
(and perhaps other attributes of type, like line-height
) change depending on the screen size (or perhaps container queries if we had them).
The core trickery comes from viewport units. You can literally set type in viewport units (e.g. font-size: 4vw
), but the fluctuations in size are so extreme that it’s usually undesirable. That’s tempered by doing something like font-size: calc(16px + 1vw)
. But while we’re getting fancy with calculations anyway, the most common implementation ended up being an equation to calculate plain English:
I want the type to go between being 16px on a 320px screen to 22px on a 1000px screen.
Which ended up like this:
html {
font-size: 16px;
}
@media screen and (min-width: 320px) {
html {
font-size: calc(16px + 6 * ((100vw - 320px) / 680));
}
}
@media screen and (min-width: 1000px) {
html {
font-size: 22px;
}
}
That’s essentially setting a minimum and maximum font size so the type won’t shrink or grow to anything too extreme. “CSS locks” was a term coined by Tim Brown.
Minimum and maximum you say?! Well it so happens that functions for these have made their way into the CSS spec in the form of min()
and max()
.
So we can simplify our fancy setup above with a one-liner and maintain the locks:
html {
font-size: min(max(1rem, 4vw), 22px);
}
We actually might want to stop there because even though both Safari (11.1+) and Chrome (79+) support this at the current moment, that’s as wide as support will get today. Speaking of which, you’d probably want to slip a font-size
declaration before this to set an acceptable fallback value with no fancy functions.
But as long as we’re pushing the limits, there is another function to simplify things even more: clamp()
! Clamp takes three values, a min, max, and a flexible unit (or calculation or whatever) in the middle that it will use in case the value is between the min and max. So, our one-liner gets even smaller:
body {
font-size: clamp(100%, 1rem + 2vw, 24px);
}
That’ll be Chrome 79+ (which doesn’t hasn’t shipped to stable but will very soon).
Uncle Dave is very happy that FitText is now a few bytes instead of all-of-jQuery plus 40 more lines. Here is Dave chucking CSS custom properties at it:
Just saw this nice explanation:
Morning devsheet: CSS `clamp` can be used for fluid typography. 🎉
— Stefan Judis (@stefanjudis) April 20, 2020
🔗 `clamp` on MDN: https://t.co/4xZpDfYoqB
Video alt: Example showing how to use `clamp` for fluid/responsive typography for an h1 element pic.twitter.com/9iiCxxXJO7
Brilliant! Please someone make a poly fill for the clamp trick in ES6.
But 4vw gets you to 22px at a screen width of only 550px, so you’re better off with the calculation.
@Matt, ain’t that the point, or isn’t this intended?
Font size is 4vw up to 550px screen width. Everything up is limited to 22px.
Agreed, I prefer being able to define when the scaling should end using viewport width, which the long
calc()
formula lets you do. I created a custom Sass mixin to make it easier to generate those formulas https://threespot.github.io/frontline-sass/documentation/#main-function-fs-scale Hope others find it useful!Just adjust it 2.2vw
This is a great tip/trick. It can really save some headache on making my website mobile-friendly. Thank you!
Good stuff there
I wonder what this means for using rem units in a project? If you’re using fluid type then I would think all your other elements should be sized using PX. Otherwise, if the user changes the base font size then all the elements will scale up except the text.
Does this still work properly if the user browser’s default font size is outside that min-max range? I have mine set at 24 px because my eyes are terrible.
I wonder what you think about the use of ch units. They are fairly well supported plus, although they are not perfect, they are quite good to cope with situations in which we want to keep the number of characters per line within a reasonable range in paragraphs. Also we could fine tune them using formulas (calc())
That’s pretty neat. I’ve been doing something similar using a scss mixin and it has worked out very good so far.
See the Pen Fluid Typography by Marc Müller
(@mkmueller) on CodePen.
RFS is a great example as well. It supports responsive sizing of other CSS properties now too and is part of Bootstrap: https://github.com/twbs/rfs
Hello,
thanks for your article and your solutions!
I have two questions:
1 – Can this formula also be used with other elements? in this case can i use it with line-height?
Because while resizing in some screens the line is high it should be decreased.
‘: min (max (1.3rem, 3vw), 35px)! important;’
2 – The min-max how it is managed, I tried to apply it, but it seems to work the opposite of how I imagine.
It seems here that 35px is the largest size, instead (1.3rem, 3vw) it is the smallest size that fits. Correct? Because I tried in a test site it works like this for me.
Thank you
I’m not sure how to correlate the two examples provided. Consider this:
It’s unclear where the
4vw
part comes in. How does that relate to the 100vw we had previously?The other example is this:
Now we have 2vw. How does that relate to the 4vw?
It’s no doubt my lack of understanding but in a whole lot of these articles, I find code examples seem to use different values but without explaining how the values between the code examples relate.
I guess adding to my confusion on my first point: why is one example declared on the
html
but the other on thebody
? Nothing in the article indicates why that is. And why is one example showing22px
while the other shows24px
?Again, it’s just very unclear to me how to relate these examples since I’m presuming they’re meant to show different ways to achieve the same effect.