How to convert pixels to em in a easy way
Asked Answered
N

9

24

I am looking for a easy way to add a line of code to a plugin of mine, to convert a couple of pixel values into em values, because the layout of my project needs to be in ems. Is there an easy way to do this, because I don't want to add a third-party plugin to the site.

Won't post the code here, as it has nothing to do with the plugin it self.

Example: 13px -> ??em

Nutrition answered 24/4, 2012 at 21:5 Comment(1)
this might help you pxtoem.com check the "learn" tabPhalansterian
M
21

I think your question is very important. Since the classes of display resolutions are rapidly increasing, using em positioning to support wide range of screen resolutions is a really appealing approach. But no matter how hard you try to keep everything in em -- sometimes you get a pixel value maybe from JQuery drag and drop or from another library, and you would want to convert this value to em before sending it back to server for persistence. That way next time user looks at the page, item would be in correct position -- regardless of screen resolution of the device they are using.

JQuery plugins are not very scary when you can review the code, specially if they are short and sweet like this plugin to convert pixel values to em as you want. In fact it is so short I will paste the whole thing here. For copyright notice see the link.

$.fn.toEm = function(settings){
    settings = jQuery.extend({
        scope: 'body'
    }, settings);
    var that = parseInt(this[0],10),
        scopeTest = jQuery('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;">&nbsp;</div>').appendTo(settings.scope),
        scopeVal = scopeTest.height();
    scopeTest.remove();
    return (that / scopeVal).toFixed(8) + 'em';
};


$.fn.toPx = function(settings){
    settings = jQuery.extend({
        scope: 'body'
    }, settings);
    var that = parseFloat(this[0]),
        scopeTest = jQuery('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;">&nbsp;</div>').appendTo(settings.scope),
        scopeVal = scopeTest.height();
    scopeTest.remove();
    return Math.round(that * scopeVal) + 'px';
};

Usage Example: $(myPixelValue).toEm(); or $(myEmValue).toPx();.

I just tested this in my application, it works great. So I thought I share.

Monetary answered 5/11, 2012 at 11:12 Comment(2)
I've never seen jQuery used like that. I'm assuming this supports string values ("3px" or "3em"), but doesn't that ask jQuery to query the document for those selectors, before you ever get to the plugin's .toPx() or .toEm()?Flied
I really don't see the point in making these a jquery / $ function - simple function toPx(ems) or function toEms(px) would be clearer to my mind.Redpoll
A
15

The following seems to do as you require, though it's based on the font-size of the parent, and of the element itself, being returned in px:

function px2em(elem) {
    var W = window,
        D = document;
    if (!elem || elem.parentNode.tagName.toLowerCase() == 'body') {
        return false;
    }
    else {
        var parentFontSize = parseInt(W.getComputedStyle(elem.parentNode, null).fontSize, 10),
            elemFontSize = parseInt(W.getComputedStyle(elem, null).fontSize, 10);

        var pxInEms = Math.floor((elemFontSize / parentFontSize) * 100) / 100;
        elem.style.fontSize = pxInEms + 'em';
    }
}

JS Fiddle proof of concept.

Notes:

  • The function returns false, if the element you're trying to convert to em is the body, though that's because I couldn't work out whether it was sensible to set the value to 1em or simply leave it alone.

  • It uses window.getComputedStyle(), so it's not going to work with IE, without some adjustments.

References:

Argile answered 24/4, 2012 at 21:19 Comment(0)
W
6

Pixels and ems are fundamentally different types of unit. You can't simply convert between them.

For instance, a user with a default font size of 16px on a site where top-level headings are styled at 200% font size, 1em may be equal to 32px. Move the heading elsewhere in the document, it could be 64px or 16px. Give the same document to a different user, it might be 30/60/15px. Start talking about a different element, and it can change again.

The closest you can come to what you want is to convert from pixels to ems+document+context+settings. But if somebody has asked you to lay out your project with ems, they will probably not be pleased that you are trying to do it in pixels then "converting".

Wether answered 24/4, 2012 at 21:11 Comment(1)
there are valid cases when you only have access to pixel value. For example when dragging a div around on the page, you might want to obtain the em value before persisting the position of the div. I think the question is perfectly valid and it is possible to convert pixels to em if you do it inside the browser. After all the browser itself converts the em values to pixels before rendering.Monetary
K
2

Usually when you want to convert px to em, the conversion happens on the element itself. getComputedStyle returns value in px which break their responsiveness. The code below can be used to help with this issue:

/**
 * Get the equivalent EM value on a given element with a given pixel value.
 *
 * Normally the number of pixel specified should come from the element itself (e.g. element.style.height) since EM is
 * relative.
 *
 * @param {Object} element - The HTML element.
 * @param {Number} pixelValue - The number of pixel to convert in EM on this specific element.
 *
 * @returns {Boolean|Number} The EM value, or false if unable to convert.
 */
window.getEmValueFromElement = function (element, pixelValue) {
    if (element.parentNode) {
        var parentFontSize = parseFloat(window.getComputedStyle(element.parentNode).fontSize);
        var elementFontSize = parseFloat(window.getComputedStyle(element).fontSize);
        var pixelValueOfOneEm = (elementFontSize / parentFontSize) * elementFontSize;
        return (pixelValue / pixelValueOfOneEm);
    }
    return false;
};

Using it would be as simple as:

var element = document.getElementById('someDiv');
var computedHeightInEm = window.getEmValueFromElement(element, element.offsetHeight);
Knell answered 31/12, 2015 at 2:2 Comment(0)
B
1

Old question, but for reference, here is something I cobbled together, scope and suffix are optional. Pass it a rem or em value as string, eg. '4em' [ you can use spaces and upper/lowercase ] and it will return the px value. Unless you give it a scope, which would be the target element for finding the local EM value, it will default to body, effectively giving you the rem value. Lastly, the optional suffix parameter [ boolean ] will add 'px' to the returned value such that 48 becomes 48px for example.

ex: emRemToPx( '3em', '#content' )

return 48 on a font-size 16px / 100% document

/**
* emRemToPx.js | @whatsnewsisyphus 
* To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
* see CC0 Public Domain Dedication <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
  var emRemToPx = function( value, scope, suffix ) {
    if (!scope || value.toLowerCase().indexOf("rem") >= 0) {
      scope = 'body';
    }
    if (suffix === true) {
      suffix = 'px';
    } else {
      suffix = null;
    }
    var multiplier = parseFloat(value);
    var scopeTest = $('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;">&nbsp;</div>').appendTo(scope);
    var scopeVal = scopeTest.height();
    scopeTest.remove();
    return Math.round(multiplier * scopeVal) + suffix;
  };
Basilbasilar answered 31/10, 2014 at 11:40 Comment(0)
F
1

I've packaged this functionality into a library, complete with parameter type checking: px-to-em

Given this HTML:

<p id="message" style="font-size: 16px;">Hello World!</p>

You can expect these outputs:

pxToEm(16, message) === 1
pxToEm(24, message) === 1.5
pxToEm(32, message) === 2

Since the OP requested a way to do this without a library, I've copied the source code of px-to-em to a live demo:

function pxToEm (px, element) {
  element = element === null || element === undefined ? document.documentElement : element;
  var temporaryElement = document.createElement('div');
  temporaryElement.style.setProperty('position', 'absolute', 'important');
  temporaryElement.style.setProperty('visibility', 'hidden', 'important');
  temporaryElement.style.setProperty('font-size', '1em', 'important');
  element.appendChild(temporaryElement);
  var baseFontSize = parseFloat(getComputedStyle(temporaryElement).fontSize);
  temporaryElement.parentNode.removeChild(temporaryElement);
  return px / baseFontSize;
}

console.log(pxToEm(16, message), 'Should be 1');
console.log(pxToEm(24, message), 'Should be 1.5');
console.log(pxToEm(32, message), 'Should be 2');
<p id="message" style="font-size: 16px;">Hello World!</p>

I learned from this answer that with getComputedStyle we can reliably obtain the divisor px value with the decimal point, which improves the accuracy of the calculation. I found that the answer by Aras could be off by over 0.5px, which caused rounding errors for us.

Fluoric answered 14/10, 2017 at 5:41 Comment(0)
R
-1

Try using this:

parseInt(myPixelValue) / parseFloat($("body").css("font-size"));
Rains answered 21/2, 2019 at 10:52 Comment(1)
Welcome to SO and thanks for your contribution. I really recommend you to annotate your answer, especially given the fact there's 8 other answers (think of a person trying to pick a relevant answer, why should they try yours? how is it helpful compared to others?)Boraginaceous
L
-1
function pixelToEm(pixel) {
   var em = pixel / 16;
   return em;
}
Lane answered 15/5, 2023 at 16:12 Comment(2)
Have a look at this answer as to why your answer is just not correct.Coagulum
In short, em is a relative unit, pixels are not. If I set the parent's font size to anything other than 16px or equivalent, this doesn't work.Buchalter
A
-3

Ems don't equal pixels in anyway. They are a relative measurement.

<span style="font-size: 1em;">This is 1em font size, which means the text is the same size as the parent</span>

<span style="font-size: 1.5em;">This is 1.5em font size, which means the text is 150% the size as the parent</span>

The base size is determined by the user-agent (browser).

Alveolate answered 24/4, 2012 at 21:11 Comment(5)
Base size is determined by itself font-size or parent(s) font-size. If anyone have font-size defined, then user-agent.Chromatograph
@Chromatograph Yes, agreed. I'm trying to say that the size at the base of everything is at the user-agent level.Alveolate
The fact that ems don't equal pixels is exactly why you might want to convert. Because if something happens to highlight the differences - like zooming in - then you want to make sure that your element will respond gracefully, which means knowing which type of units it's using.Halfblood
@Halfblood Use em and then you don't have to worry about it. Why use pixels at all?Alveolate
@Alveolate That's exactly what the OP is trying to do. The original question is about converting pixels to em. So they're getting a size value from somewhere, and it's in pixels, and they want it to be em in order to be consistent.Halfblood

© 2022 - 2024 — McMap. All rights reserved.