Recently, I needed to implement a design that scaled the space between components as the viewport changed size. The requirement is nothing new but I wanted to find a way to acheive it without having to re-declare multiple style rules in a media query. This article explains the technique I used.
The design in question starts out as a linear list of elements that are cloesely spaced to make best use of a small viewport. As the size of the viewport increases, the elements begin to flow into columns and grids until we reach the final "desktop" variant. At key points in the design, font sizes and the space between elements need to increase to make use of the extra space afforded by a larger viewport — nothing new so far.
The following example is a bare-bones responsive layout with fixed font sizes and element spacing. When viewed on a small viewport the page looks okay, but as the viewport gets larger, more whitespace and larger font sizes are needed.
In this example, to increase the spacing between elements, most of us would write a media query or two to redeclare the relevant CSS properties with new values — while this works, it's not particularly efficient (re-declaring the same rules over and over never sits well with me). If you use utility classes to control things like element spacing then the problem is not as bad, but you'll probably still end up writing duplicate rules.
I wanted to experiment with ways of achieving this without having to write a lot of additional CSS. Here's what I came up with...
Enter, responsive rem
units
The techinque uses rem
units to set a baseline for property values. Style properties such as padding
and margin
can then be defined using rem
units. A combination of media queries and font-size
adjustments are used to scale these values at key points in the design without affecting the page font or any em
based property values. Scaling of rem
units is controlled using the following CSS:
Let's walk through that...
The font-size
value of the html
element is set to target small viewports — for the purposes of this demo, I've settled on a size of 80%
. When the viewport reaches a minium width of 35em
the font size of the <html>
element is doubled, which doubles the size of a rem
unit. Increasing the font size of the <html>
element will scale fonts and other elements on the page. To correct this, the font size of the <body>
element is also halved. Fonts now render at the same size, but rem
units are now twice the size.
If we go back to the first demo and switch out any padding or margin em
units for rem
s, it's now possible to control element spacing using just the font-size
property. The next demo show this in practice. If you resize the viewport you'll see the space between various elements changes:
Scaling fonts
Now we're able to scale space, we can leverage the same technique to scale fonts as the viewport changes size. We do this by increasing the <body>
font size:
In this example we're doubling the size of the font when then viewport width reaches 35em
. As demonstrated above, applying font-size of 50%
the the <body>
element would counter the doubling effect of applying 160%
to the <html>
element. By applying 75%
we're only reducing the doubling effect by half, which doubles the <body>
font size.