Responsive Typography Using Calc(), VW, and Sass Superpowers
by Nate York - June 28, 2017 - 4 minute read
How to precisely scale text as the viewport expands and contracts. I've been pretty fascinated by MadeByMike's calc() wizardry over the last couple of weeks, and I really wanted to use it, since adding a bunch of breakpoints to manage font size changes across viewports is quite frankly a pain in the butt to maintain, and I hate inefficiency. Turns out I have exactly the right project to experiment with, so I took the plunge...
What's This All About?
The concept behind the solution is pretty simple: declare the smallest font size you want to use on small viewports, the biggest size you want to use on large ones, and let technology handle scaling the text as the viewport width changes.
How about we just look at a demo? Go ahead and make your browser wider/narrower and watch the magic… I’ll wait.
In this example, the size of text on viewports between 480px and 1200px wide is calculated dynamically within the minimum and maximum size restraints. Viewport widths below or above the specified range are styled with the min/max sizes respectively, without any calculation.
What a time to be alive!
You Wanted to Change This Magic?
Only slightly. Mike's solution was intended to handle all typography sizing in one fell swoop using the :root CSS selector, meaning all typography would be based off a single max font size (your H1, for instance), and a min font size (your body text, perhaps). The solution then sizes all other typography according to that, as you can see in his original demo linked at the beginning of this piece.
While this is super neat, works great, and may be perfect for your situation, I wasn't fully satisfied with how things looked, and wanted more precise control over each typographical element. I could have copied and pasted over the code and reworked it for each, but that's gross, and even worse than the unmaintainable fiasco we were in before this...
Sass to the Rescue!
Sass maps are seriously the best. I'll spare you the deep dive, but in general, Sass maps are nestable data types that accept key/value pairs. Data in these maps can be iterated upon, merged, and parsed in pretty much any way you can imagine, allowing us to automate the writing of complex CSS. Learn them, love them, and let them do your heavy lifting.
In this example, I have a map set up for fonts, with a nested map for different sizes which contain main and max values for each element I want to define sizes for. I'm using an @each operator to iterate over each element in the map and create the necessary selectors and styles to handle the responsive calculation. NEAT!
And the compiled CSS looks like this:
Of course, we're responsible front end developers, so I’ve converted the font size values in the map to use Sass variables, which we can toss in a settings partial. Then, we can easily maintain this whole thing just by updating the variable definitions. You're welcome, future Nate!
Do Browsers Support This?
That’s cool and all, but I can't use it because this sounds fancy and some browsers hate fancy. Right?
Nonsense. Unless you're dealing with old IE or Opera Mini, you're good to go as-is. Even if you are dealing with browsers that don’t support either vw or calc(), they simply fall back to the standard font-sizing techniques in the solution (the min and max font sizes). The only issue that would arise is that you'd be displaying the smallest font size all the way up to 1200px, but you could craft a more elegant fallback plan if you need it.
What Next?
This is definitely production-ready. However, I'm curious about adding on to the calculation to add relative unit support (REM w/px fallback, specifically). Beyond that, I only just started tinkering, so I haven't used it enough to know the all the ins and outs quite yet. If you have ideas, I’d love to hear them!