Cómo convertir píxeles a em de una manera fácil

8 minutos de lectura

avatar de usuario
usuario759235

Estoy buscando una manera fácil de agregar una línea de código a un complemento mío, para convertir un par de valores de píxeles en valores em, porque el diseño de mi proyecto debe estar en ems. ¿Hay una manera fácil de hacer esto, porque no quiero agregar un complemento de terceros al sitio?

No publicaré el código aquí, ya que no tiene nada que ver con el complemento en sí.

Ejemplo: 13px -> ??em

  • esto podría ayudarte pxtoem.com revisa la pestaña “aprender”

    – chepe263

    24 de abril de 2012 a las 21:07

avatar de usuario
Aras

Creo que tu pregunta es muy importante. Dado que las clases de resoluciones de pantalla están aumentando rápidamente, usar el posicionamiento em para admitir una amplia gama de resoluciones de pantalla es un enfoque realmente atractivo. Pero no importa cuánto intente mantener todo en em, a veces obtiene un valor de píxel tal vez de arrastrar y soltar de JQuery o de otra biblioteca, y querrá convertir este valor en em antes de enviarlo de vuelta al servidor para persistencia. De esa forma, la próxima vez que el usuario mire la página, el elemento estará en la posición correcta, independientemente de la resolución de pantalla del dispositivo que esté utilizando.

Los complementos de JQuery no dan mucho miedo cuando puedes revisar el código, especialmente si son breves y sencillos como este complemento para convertir valores de píxeles a em como quieras De hecho, es tan corto que pegaré todo aquí. Para ver el aviso de derechos de autor, consulte el enlace.

$.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';
};

Ejemplo de uso: $(myPixelValue).toEm(); o $(myEmValue).toPx();.

Acabo de probar esto en mi aplicación, funciona muy bien. Así que pensé en compartir.

  • Nunca he visto jQuery usado así. Supongo que esto admite valores de cadena ("3px" o "3em"), pero ¿eso no le pide a jQuery que consulte el documento para esos selectores, antes de llegar al complemento? .toPx() o .toEm()?

    –Michael Lewis

    6 de enero de 2017 a las 19:21

  • Realmente no veo el punto de hacer de estos una función jquery / $: la función simple toPx (ems) o la función toEms (px) sería más clara para mi mente.

    – Zampullín.123

    12 de noviembre de 2018 a las 19:44

avatar de usuario
David Tomás

Lo siguiente parece hacer lo que necesita, aunque se basa en el font-size del padre, y del propio elemento, siendo devuelto en 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 prueba de concepto.

Notas:

  • La función devuelve falso, si el elemento al que intenta convertir em es el bodyaunque eso se debe a que no pude determinar si era sensato establecer el valor en 1em o simplemente déjalo en paz.

  • Usa window.getComputedStyle()por lo que no funcionará con IE, sin algunos ajustes.

Referencias:

Los píxeles y ems son fundamentalmente diferentes tipos de unidades. No puede simplemente convertir entre ellos.

Por ejemplo, un usuario con un tamaño de fuente predeterminado de 16 píxeles en un sitio donde los encabezados de nivel superior tienen un estilo de tamaño de fuente del 200 %, 1 em puede ser igual a 32 píxeles. Mueva el encabezado a otra parte del documento, podría ser 64px o 16px. Entregue el mismo documento a un usuario diferente, podría ser 30/60/15px. Empiece a hablar de un elemento diferente, y puede cambiar de nuevo.

Lo más cerca que puede llegar a lo que desea es convertir de píxeles a ems+document+context+settings. Pero si alguien le ha pedido que diseñe su proyecto con ems, probablemente no estará contento de que esté tratando de hacerlo en píxeles y luego “convertir”.

  • hay casos válidos en los que solo tiene acceso al valor del píxel. Por ejemplo, al arrastrar un div por la página, es posible que desee obtener el valor em antes de conservar la posición del div. Creo que la pregunta es perfectamente válida y es posible convertir píxeles a em si lo hace dentro del navegador. Después de todo, el navegador convierte los valores em en píxeles antes de renderizar.

    – Aras

    5 de noviembre de 2012 a las 9:55

Pregunta anterior, pero como referencia, aquí hay algo que improvisé, el alcance y el sufijo son opcionales. Pásele un valor rem o em como cadena, por ejemplo. ‘4em’ [ you can use spaces and upper/lowercase ] y devolverá el valor px. A menos que le dé un alcance, que sería el elemento de destino para encontrar el valor EM local, se establecerá de forma predeterminada en el cuerpo, lo que le dará el valor rem. Por último, el parámetro de sufijo opcional [ boolean ] agregará ‘px’ al valor devuelto de modo que 48 se convierta en 48px, por ejemplo.

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

devuelve 48 en un documento de tamaño de fuente 16px / 100%

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

Por lo general, cuando desea convertir px a emla conversión ocurre en el propio elemento. getComputedStyle devuelve valor en px que rompen su capacidad de respuesta. El siguiente código se puede utilizar para ayudar con este problema:

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

Usarlo sería tan simple como:

var element = document.getElementById('someDiv');
var computedHeightInEm = window.getEmValueFromElement(element, element.offsetHeight);

avatar de usuario
jackson

He empaquetado esta funcionalidad en una biblioteca, completa con verificación de tipo de parámetro: px-to-em

Dado este HTML:

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

Puede esperar estos resultados:

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

Dado que el OP solicitó una forma de hacer esto sin una biblioteca, copié el código fuente de px-to-em a una demostración en vivo:

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>

Aprendí de esta respuesta que con getComputedStyle podemos obtener de forma fiable el valor px del divisor con el punto decimal, lo que mejora la precisión del cálculo. Descubrí que la respuesta de Aras podría tener un error de más de 0,5 px, lo que nos provocó errores de redondeo.

avatar de usuario
Tehila

Intenta usar esto:

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

  • Bienvenido a SO y gracias por tu contribución. Realmente te recomiendo que anotes tu respuesta, especialmente dado que hay otras 8 respuestas (piensa en una persona que intenta elegir una respuesta relevante, ¿por qué debería probar la tuya? ¿Cómo es útil en comparación con otras?)

    – YakovL

    21 de febrero de 2019 a las 14:03

¿Ha sido útil esta solución?