Update: jQuery Plugin for Retaining Scalable Interfaces with Pixel-to-Em Conversion

April 2020 note: Hi! Just a quick note to say that this post is pretty old, and might contain outdated advice or links. We're keeping it online, but recommend that you check newer posts to see if there's a better approach.

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.

Why ems, anyway?

Permalink to 'Why ems, anyway?'

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.

How do ems work?

Permalink to 'How do ems work?'

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.

Where ems are often abandoned

Permalink to 'Where ems are often abandoned'

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.

So how does the plugin work?

Permalink to 'So how does the plugin work?'

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.

Sample output:

Permalink to 'Sample output:'
var pixelValue = 256;
var emValue = $(pixelValue).toEm();
==> returns '25.6em'

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:

Sample output using a scope element:

Permalink to 'Sample output using a scope element:'
var pixelValue = 256;
var scopeElement = $(myElement); //element being used for scope. It has a font size of 14px.
var emValue = $(pixelValue).toEm({'scope': scopeElement});
==> returns string "18.29em"

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.

But what about ems to pixels?

Permalink to 'But what about ems to pixels?'

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.

For example

Permalink to 'For example'

As an example, let’s assume we’re injecting a div into some nested markup and it needs to appear 80px wide, while set using ems. Here’s our sample markup and CSS:

HTML:

Permalink to 'HTML:'
<div class="A">
    <div class="B">
        <div class="C">
            <div class="D"></div>
        </div>
    </div>
</div>

CSS:

Permalink to 'CSS:'
body{ font-size: 62.5%; }
.A { font-size: 2em; }
.B { font-size: 2em; }
.C { font-size: .5em; }
.D { font-size: 8.5em; }

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.

Visual demo

Permalink to 'Visual demo'

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).

Demo page

Sweet! How do I use it?

Permalink to 'Sweet! How do I use it?'

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.

Download (and help us improve) the code

Permalink to 'Download (and help us improve) the code'

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.

All blog posts