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...
The techinque uses
rem units to set a baseline for property values. Style properties such as
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...
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
rems, 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:
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.