Like many blogs, this site is basically just text, so options for making it visually interesting are mostly limited to typography. I quite like using big, bold headlines for this, and think the effect at
3.5rem on a large display is pretty nice.
However, that aspect of the design doesn’t work very well on a small display, and is just plain bad when the headline is long and/or includes long words:
I really want at least the first paragraph of content to be readable on a small display without having to scroll. Media queries could help, but in cases like this they’re a bit of a blunt instrument. I’d need to set one or more breakpoints at which the size would increase, accounting for both width and height, and there’d still be some sizes at which it wasn’t quite right.
CSS has other tools available to us in the form of functions, where we can compute values based on various other values, including the current font size and the viewport width and height.
After some experimentation, here’s what I have now:
font-size: clamp(2rem, min(10vw, 10vh), 3.5rem);
2rem declaration is in as a safe fallback for older browsers; if the syntax of the next declaration isn’t recognised, it’ll be ignored and the
2rem will stand.
Use whichever is the smaller of 10% of the viewport width or 10% of the viewport height, but prevent it from being any smaller than 2x the root font size or any larger than 3.5x the root font size.
1em provides an appropriate leading based on the computed font size.
min() and other similar functions are things you can’t do at build time with preprocessors, because the values are evaluated at runtime.
My example isn’t anything special, but I think the ability to nest functions, as well as their support for mixing units as I have done here, makes them very powerful for achieving precision in contexts that are both complex and dynamic, and adaptiveness in ways that aren’t tied to specific pixel breakpoints. This is especially true of
calc(), which (as I sometimes forget) is supported all the way back to Internet Explorer 9.
- As you might expect, we have
max()to go with
- Though most examples show them used with two values,
max()can take as many different values as you’d like
- Take care with
vh; things like the disappearing browser chrome on iOS Safari can make it behave in unexpected ways, so I tend to avoid it for layout - but it’s great for things like this
The 10% number just came out of trial and error. ↩︎