menu

Using em units in CSS layout allows for page components to scale in
unison with a user’s font-size preferences. But developing in ems within
dynamically updating web apps can be very tricky. In an earlier lab
article,
we released a script to quickly convert pixel values to ems (and vice
versa) to support page scalability throughout a web site or application.
We’ve rewritten the plugin to better follow jQuery syntax and reduce
code weight, and are now releasing an updated version for download.

In CSS layouts, ems are often used in place of pixels to allow elements
and text to scale in unison. Although pixels tend to be easier to use
and more precise, many browsers such as Internet Explorer can not scale
text that is set in pixels. By using ems for not only our text, but for
setting the heights and widths of structural elements, some or all of
the page layout can also scale in proportion to the text size.

In brief, an em is a relative unit that is equivalent to the height of a
font. Since most browsers’ default font size is 16px, we can assume that
1em is equal to 16px; meaning that 12px is equal to 0.75em, and 10px
type is equal to 0.625em. As you can see, it can be quite tedious to
calculate em values this way, and luckily a method was developed by
Richard Rutter to alleviate the problem.
By simply setting the body element’s font size to 62.5%, the value of
1em becomes 10px. This allows for nice and easy calculations to ems by
simply dividing a pixel value by 10.

While that cuts down on some of the conversion work, the value of 1em
can still vary depending on parent/child relationships in the DOM. For
every element on the page, the value of 1em is calculated based on the
font size of its parent element. This means that while a paragraph may
have a font size of 1.2em and appear to be 12px tall, all of its
children will exist in a world where 1em is equal to 12px instead of 10.
Which, in a way, leads us back to where we started.

Developing an em-based stylesheet can be confusing, but it’s manageable
once you understand the complexities of font-size inheritance. We find
that the problems more often occur outside of the stylesheet, when
elements are inserted or modified with javascript. During animation
effects or modifications to the DOM, many javascript libraries style
elements using pixels to avoid the possibility of conflicts, and while
pixels are often desired and are a good default, we usually want our
modifications to fit within a scalable interface. For this reason, we’ve
come up with a method that converts pixel values to ems on the fly, and
always calculates within the scope it is given.

When called, our plugin converts a given pixel value to ems. By default,
it uses the body’s font size for scope, but a scope property (in the
form of a jQuery selector) can be passed to handle conversions that are
relative to that element’s font size.

The sample above may look like a simple division of 10, but the script
actually checks the font size of the body before calculating so it will
work in many environments. To demonstrate how scope is used, consider
the following example which uses a scope property:

We can see that pxem.jQuery.js has used the font size of the scope
element for its calculation above. Using a scope parameter may be
particularly useful for figuring out dimensions when inserting an
element into the scope element.

Don’t worry, we didn’t leave you hangin’! A second included plugin
called ‘toPx’ defines the direction of the conversion. Simply call the
.toPx method instead and the script will convert your em value to
pixels. Keep in mind that the plugin expects a number value, not a
string, so use 7.5 instead of '7.5em'. The following demo
demonstrates the flexibility and capabilities of this plugin.

If you recall from above, em font-sizes are calculated based on their
entire parent hierarchy, so depending on where we inject our div in the
markup above, its em-based width will need to be quite different in
order to appear 80px wide. For example, if we inject it into div.A, we
would need to calculate an em value based on half that of what it would
be if it were injected into the body, due to its 2em font size.
Furthermore, if we were to inject the div into div.D, we would need to
calculate our width based on 8.5 x .5 x 2 x 2, due to all of the
inherited font sizes in the nested divs.

Thankfully, this plugin handles all of the complex calculation logic for
us. For example, to get the appropriate width value for injecting in
div.A, we could do this:

$(80).toEm({scope: '.A' });

…which would return '4em', giving us the width we could then set on
our div.

Likewise, to get our width value for injecting into div.D, we could do
this:

$(80).toEm({scope: '.D' });

…which would return '0.470588em;'. A very different value, but equal
to 80px in this context nonetheless.

The demo below contains the markup and CSS shown above. Here’s what’s
happening: Using jQuery, we append a new div (shown in gray below) to
each existing div, and use our plugin to calculate em-equivalent 200px,
which we use to set that div’s width. The value of 1em varies depending
on the font-size inheritance of the parent element into which the div is
injected. The plugin script factors in that font-size inheritance and
calculates a necessary multiplier value to make all divs visually equal
in width, while their actual width values vary greatly (as shown in the
labels below).

First, you’ll need the jQuery javascript library, which is free and can
be downloaded at jQuery.com. Then grab one of
the javascript file linked below and either paste its contents into your
javascript file or link to it as a standalone.

The pixel-to-em plugin code is open source and available in a git
repository,
jQuery-Pixel-Em-Converter.
If you think you can help on a particular issue, please submit a pull
request and we’ll review it as soon as possible.

600

Comments

<div id="commentNumber1" class="commentEntry">

<p>Thanks; this looks awesome.

Will certainly be using this in my next project.

</div>
<p class="posted"><a href="#commentNumber1">Comment</a> by

Ben
on 05/21 at 12:45 PM

<div id="commentNumber2" class="commentEntry">

<p>would not it be better to return a number for further calculations, like adding or removing padding/margin widths??

any way, it is really worth the additional effort, only for scaling and only in IE?? the only people that i know that know that there is a scaling feature in the browser are all developers…

<p>This is a really useful plugin but had a question in regards to the API. The hardest part for me was wrapping my head around passing in a pixel value as the selector. Would think the following would make more sense:

var em = $(’body’).toEm( 256 );

Then you could accept a second attribute that would not return the unit of measure (to allow for easier calculations):
var em = $(’body’).toEm( 256, false ) // return 25.6 instead of 25.6em

<p>@Michael Moossen: Good question. Returning just a number might be handy, but then you’d have to concatenate it with +’px’ or +’em’ every time. We did it this way since we almost always used it to translate a result, rather than using it in a step along the way in a calculation.

As for your question about users knowing about browser zoom features, I guess it’s hard to make assumptions about that, but we tend to write CSS in flexible units so pages at least scale vertically when resized. It doesn’t end up causing any additional development time to code this way, and often allows us to design proportionally so elements can be scaled through parent font size if we need to make large-scale adjustments.

@Jonathan: nice idea. Maybe something we should consider…

</div>
<p class="posted"><a href="#commentNumber6">Comment</a> by

Scott
(Filament) on 10/15 at 11:15 AM

<div id="commentNumber7" class="commentEntry">

<p>@Antony Kennedy: indeed i have not done much work focused on accessibility. but what has that to do with this? could you please be a little bit more constructive?

@jonathan: i also like the idea

@scott: yes, of course, most of the time you (and always more, i) will use proportional sizes, but there are exceptions: in my case, a 5px wide, white frame (margin) around a thumbnail… or the border of this very textarea where all measures are in em except the 1px border!
On the browser’s zoom feature, i was just telling my experience.

<p>Running your sample code in Firefox 3.6 returns 21.333333 not 25.6. This would be extremely useful if it were accurate. I’m trying to set the width of my buttons based on the number of characters in them. Everything is working except multiplying my string length by the ems calculation. I need to multiply by the body font-size, but jquery without a plugin like this returns it in pixels, which is then not scalable. My font-size is set as .74em in my stylesheet, this jquery returns the body font-size as 11.833333px, when I strip the “px” and convert to ems it returns .916666667 instead of .74. Why?

</div>
<p class="posted"><a href="#commentNumber9">Comment</a> by

BenDZN
on 03/29 at 11:37 AM

<div id="commentNumber10" class="commentEntry">

<p>I have the same problem in IE vs. Firefox.&nbsp; JQuery returns my header font-size as 20px in IE and 18px in Firefox, so the pixel to em calculation is off for the purposes of resizing.&nbsp; Incidentially, the Firefox calculation is correct as per my stylesheet.&nbsp; Does anyone know how to fix this?

</div>
<p class="posted"><a href="#commentNumber10">Comment</a> by

Jamie
on 06/11 at 02:46 PM

<div id="commentNumber11" class="commentEntry">

<p>Why append a temp div with font-size 1em and get its height?&nbsp; Why not just divide the pixel value by parseFloat($element.css("font-size")) where $element is the body by default?

</div>
<p class="posted"><a href="#commentNumber11">Comment</a> by

David
on 04/13 at 05:53 PM

<div id="commentNumber12" class="commentEntry">

<p>As for your question about users knowing about browser zoom features, I guess it’s hard to make assumptions about that, but we tend to write CSS in flexible units so pages at least scale vertically when resized. It doesn’t end up causing any additional development time to code this way, and often allows us to design proportionally ..