jQuery/[removed] convert pixels to em in a easy wa

2019-01-14 02:57发布

问题:

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.

Thanks.

Example: 13px -> ??em

回答1:

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.



回答2:

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:

  • Math.floor().
  • parentNode.
  • parseInt().
  • tagName.
  • toLowerCase().
  • window.getComputedStyle().


回答3:

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



回答4:

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


回答5:

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


回答6:

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.



回答7:

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



回答8:

Check this small script out: https://github.com/normanzb/size

it helps you converting the units as long as you pass in a reference dom element