Not long ago, I designed what seemed like a tricky heading to implement. For our upcoming Ancient City Ruby conference, I placed two lines of text on either side of “450” (the number of years St. Augustine has been a city), taking up the full width of the containing column. Oh, yeah, and I wanted this heading to be responsive.

If you’re not using Javascript to determine browser width — which I wasn’t, for the sake of finding a CSS-only solution — you might think you could use percentages or rems to make this work. But those solutions don’t cause the text to resize correctly, because percentages and rems are relative to their parents and can’t calculate the size of the browser window.

Viewport units are nice because they let us create elements relative to the viewport instead of a container. That’s why, within a container that has a max-width, you can still set elements to take up space according to the viewport size, something you can’t do with percentages or rems.

This layout was a good test case for viewport units, which I’d heard of but never used before. Viewport units — vw (viewport width), vh (viewport height), vmax (the larger of the two), and vmin (the smaller of the two) — represent 1% of the viewport size, and are fully supported by the big three (Firefox, Chrome, and Safari). IE 9+ has partial support (because it uses vm instead of vmin), and all modern mobile browsers except Opera support viewport units. There’s some bugginess in iOS 7 related to vh, but there are workarounds if you need them. We won’t be using vh in this example, though.

First I created a containing element called .column, with a span for each of the elements inside:

.column%span.opening St. Augustine celebrates
%span.number 450
%span.closing years of history in 2015

I positioned .column relatively, with a width of 80% and max-width of 1000px. (Again, this wrapper won’t affect child elements that have viewport units. This is because viewport units remain relative to the viewport instead of parent containers.)

.columntext-align:centerposition:relativewidth:80%max-width:1000px

I absolutely positioned .first and .last on the left and right edges of .column and added a transition effect to smooth resizing motion.

I styled each of the span elements, and added a tiny bit of left margin to .number because it isn’t actually dead center. “St. Augustine celebrates,” the preceding span, is a bit longer than the last, “years of history in 2015,” so .number needed to be nudged a bit.

Finally, I implemented vw units for the text, with rem sizes for fallbacks (looking at you, IE 8). The font size is determined by the current viewport width, so as you resize your browser, the letters fill the amount of space specified — and at most sizes, this works really well.

Of course, I wanted this layout to work at different breakpoints. I wrote rules to create a pixel-based font size when the viewport reaches the largest comfortable width, because I didn’t want the text to grow to infinity, and since the wrapper has a max-width the text could eventually outgrow it. To account for this, I set the font size for .open and .close to 24px and .number to 129px beyond a browser width of 1300px.

When sizing down, there wasn’t a whole lot to change. I dragged my browser window back and forth to eyeball top margins for .opening and .closing, which I changed at different breakpoints to keep the content vertically centered on either side of .number.

I set rules at max-widths of 480px and 680px to keep the text at a smaller viewport width on mobile devices. For viewports under 680px, the text stacks for readability instead of centering.

I was pretty happy with how the final heading turned out. (The live version is no longer available, but try it for yourself!)

You can use viewport units on anything, not just text. For my purposes, I found viewport units to be really helpful with font-size, and knowing it’s pretty cross-browser friendly is a compelling reason to use it in the future. Try implementing viewport units in your next project and see where it takes you.