Dynamic, Responsive font-sizes and spacing using em units and JavaScript
Dynamic responsive font-sizing is something I see missing on many “responsive” websites. Breakpoints are nice but I have better things to do with my time than defining infinite font-size adjustments. (so do you!)
To implement this, we’re going to take advantage of the em
font sizing unit in CSS.
Click here to see what I'm talking about:
codepen.io/lawrencealan/full/eJqlu
Text sizing using the em
unit
A single em
is equal to the current font-size of the closest parent which has a font-size
set.
If the font-size of the document is 12pt, 1em is equal to 12pt.
If the font-size of the document is 10px, 0.5em is equal to 5px.
If the font-size of the document is 8px but you have an element with a font-size of 20px, your target element will base it’s font-size off of the closest parent element up the chain with a font-size set. So if you set your target element font-size to 2em, it’s going to hit the 20px font-size’d parent and render at 40px font size.
You can also chain em
scaling — watch out for this, it’s easy to overlook:
<div style="font-size:10px">
<div style="font-size:1.5em">
a
<div style="font-size:1.5em">
b
<div style="font-size:1.5em">
c
</div>
</div>
</div>
</div>
Produces each letter 1.5 times the size of the enclosing div, so the font-size for "a" would be 15px, "b" would be 22.5px, and "c" would be 33.75px.
Other em
unit fun
You can also adjust things like, positions, padding, margins, dimensions pretty much anything that accepts a px
value in CSS will accept an em
size
For instance, if we change the above inline CSS definitions to margin-left
instead of font-size
, we can get an automatically increased margin for nested child elements!
This sort of thing comes in really handy, especially when you set a minium base pixel size in your dynamic sizing code.
Making the sizing relative, and giving width priority
Using jQuery, we'll get the width and height of the viewport, and if the width is a greater dimension than the height, we'll give available horizontal area priority when calculating the font-size to apply to our elements.
You can have elements inside our "dfs" classed elements that use em
font size definitions.
Note that your dfs
classed element will have inline font-size
and line-height
overridden. So you will need an inner element styled with em
font sizing. Only font sizes declared in the em
unit will resize, pixel font sizes are fixed in size, not relative.
(function ($) {
var _window = { w: window };
function adjust_dfs(e) {
var _fsx, _fsy, _fs, _adj, _n;
// get the window dimensions
_window.x = _window.w.innerWidth || _window.e.clientWidth || _window.g.clientWidth;
_window.y = _window.w.innerHeight || _window.e.clientHeight || _window.g.clientHeight;
// we get the "base font-size" by dividing into our "core" dimension on 1024x768 and multiplying
// the result by 16 (initial font size for most
var _fsx = (_window.x / 1024) * 16;
var _fsy = (_window.y / 768) * 16;
// if width > height, then we get the average font size from width and height calculations
// otherwise, if the width of the window is less than the height, we use the width based size
var _fs = (_window.x > _window.y ? ((_fsx + _fsy) * 0.5) : _fsx );
// our minimum base font-size should be 8px, or whatever you want
if (_fs < 8) {
_fs = 8;
}
// our maximum base font-size should be 20px, or whatever you want
if (_fs > 20) {
_fs = 20;
}
// we bring the decimal point down to two places, so our performance doesn't take a hit
// when trying to calculate text at a size of 8.1294129836928352903862391em
_n = parseFloat(_fs, 10).toFixed(2);
// setup the css definition object once
_adj = {
fontSize: _n + 'px'
};
// set the base font size onto our dfs class elements
$('.dfs').css(_adj);
}
// run once on load
adjust_dfs();
// run on window resize
$(window).on('resize', adjust_dfs);
})(jQuery);
And the HTML:
<html>
<body>
<h1 class="dfs">
<span>Test Heading</span>
</h1>
<p class="dfs">
<span>Static sized text, and also</span> <em>dynamic</em>
</p>
<div class="dfs" id="example_div">
<header>Lipsum.</header>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio sint nesciunt odio ad eaque! Iste quod fugiat debitis culpa quas nobis! Blanditiis recusandae illo nam tempora quod omnis fugiat totam.</p>
</div>
</body>
</html>
With CSS (SCSS):
body {
padding:4px;
h1.dfs {
margin-left:2em;
span {
font-size:4.8em;
line-height:0.8em;
}
}
p.dfs {
margin-left:3em;
span {
font-size:10px;
}
em {
font-size:2em;
}
}
#example_div {
background: #eeeeee;
margin:2em;
padding:1.5em 1em .5em 1em;
width:24em;
header {
font-size:4em;
line-height:0.8em;
}
p {
font-size:12px;
text-align:justify;
}
}
}
Again, you can see this in action here:
codepen.io/lawrencealan/full/eJqlu