jQuery/JavaScript: convert pixels to em in a easy way

两盒软妹~` 提交于 2019-11-27 20:06:41
Aras

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.

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:

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

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;
  };

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

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.

Try using this:

parseInt(myPixelValue) / parseFloat($("body").css("font-size"));

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!