web-dev-qa-db-fra.com

Convertir em en px en Javascript (et obtenir la taille de police par défaut)

Dans certaines situations, il peut être utile d'obtenir la largeur de pixel exacte d'une mesure em. Par exemple, supposons que vous ayez un élément avec une propriété CSS (comme une bordure ou un remplissage) qui est mesuré en ems, et vous devez obtenir la largeur de pixel exacte de la bordure ou du remplissage. Il y a une question existante qui touche à ce sujet:

Comment puis-je obtenir la taille de police par défaut en pixels en utilisant JavaScript ou JQuery?

Cette question demande comment obtenir la taille de police par défaut - qui est nécessaire pour convertir une valeur relative em en une valeur exacte px.

Cette réponse a une assez bonne explication sur la façon d'obtenir la taille de police par défaut d'un élément:

Comme les ems mesurent la largeur, vous pouvez toujours calculer la taille de police exacte en pixels en créant un div de 1000 ems de long et en divisant sa propriété de largeur du client par 1000. Il me semble que les ems sont tronqués au millième le plus proche, vous avez donc besoin de 1000 ems pour éviter une troncature erronée du résultat en pixels.

Donc, en utilisant cette réponse comme guide, j'ai écrit la fonction suivante pour obtenir la taille de police par défaut:

function getDefaultFontSize(parentElement)
{
    parentElement = parentElement || document.body;
    var div = document.createElement('div');
    div.style.width = "1000em";
    parentElement.appendChild(div);
    var pixels = div.offsetWidth / 1000;
    parentElement.removeChild(div);
    return pixels;
}

Une fois que vous avez la taille de police par défaut, vous pouvez convertir n'importe quelle largeur de em en px en multipliant simplement les ems par la taille de police par défaut de l'élément et en arrondissant le résultat:

Math.round(ems * getDefaultFontSize(element.parentNode))

Problème: Le getDefaultFontSize est idéalement censé être une simple fonction sans effet secondaire qui renvoie la taille de police par défaut. Mais cela [~ # ~] a [~ # ~] un effet secondaire malheureux: il modifie le DOM! Il ajoute un enfant puis le retire. L'ajout de l'enfant est nécessaire pour obtenir une propriété offsetWidth valide. Si vous n'ajoutez pas l'enfant div au DOM, la propriété offsetWidth reste à 0 car l'élément n'est jamais rendu. Même si nous supprimons immédiatement l'élément enfant, cette fonction peut toujours créer des effets secondaires imprévus, tels que le déclenchement d'un événement (comme l'événement onpropertychange d'Internet Explorer ou DOMSubtreeModified d'Internet Explorer) qui écoutait l'élément parent .

Question: Existe-t-il un moyen d'écrire une fonction getDefaultFontSize() vraiment sans effet secondaire qui ne déclenchera pas accidentellement des gestionnaires d'événements ou ne provoquera pas d'autres effets secondaires involontaires?

51
Channel72

Edit: Non, il n'y en a pas.

Pour obtenir la taille de police rendue d'un élément donné, sans affecter le DOM:

parseFloat(getComputedStyle(parentElement).fontSize);

Ceci est basé sur la réponse à cette question .


Modifier:

Dans IE, vous devez utiliser parentElement.currentStyle["fontSize"], mais il n'est pas garanti de convertir la taille en px. C'est donc fini.

De plus, cet extrait ne vous donnera pas la taille de police par défaut de l'élément, mais plutôt sa taille de police réelle, ce qui est important si une classe et un style lui sont associés. En d'autres termes, si la taille de police de l'élément est 2em, vous obtiendrez le nombre de pixels en 2 ems. À moins que la taille de la police ne soit spécifiée en ligne, vous ne pourrez pas obtenir le bon taux de conversion.

26
mgiuffrida

J'ai une meilleure réponse. Mon code stockera la valeur 1em dans unit-px dans la variable em.

  1. Placez ce div n'importe où dans votre code HTML

    <div id="div" style="height:0;width:0;outline:none;border:none;padding:none;margin:none;"></div>
    
  2. Placez cette fonction dans votre fichier JavaScript

    var em;
    function getValue(id){
        var div = document.getElementById(id);
        div.style.height = 1em;
        em = div.offsetHeight;
    }
    

Maintenant, chaque fois que vous appellerez cette fonction 'getValue' avec l'id de ce test div en paramètre, vous aurez un nom de variable em qui contiendra la valeur de 1 em en px.

7
Dhruv Singhal

Si vous avez besoin de quelque chose de rapide et sale (et basé sur la taille de police de base du corps, pas un élément), j'irais avec:

Number(getComputedStyle(document.body,null).fontSize.replace(/[^\d]/g, ''))

 Number(  // Casts numeric strings to number
   getComputedStyle(  // takes element and returns CSSStyleDeclaration object
     document.body,null) // use document.body to get first "styled" element
         .fontSize  // get fontSize property
          .replace(/[^\d]/g, '')  // simple regex that will strip out non-numbers
 ) // returns number
3
Anthony

La solution suivante utilise la recherche binaire et window.matchMedia pour connaître la largeur em d'une fenêtre. Nous divisons ensuite la largeur de la fenêtre avec la largeur des pixels de la fenêtre pour obtenir le résultat final. Aucun DOM impliqué, effets secondaires gratuits! En termes de performances, il faut environ 8 itérations à environ 0,2 ms sur mon ordinateur.

const singleEmInPixels = getSingleEmInPixels();
console.log(`1em = ${singleEmInPixels}px`);

/**
 * returns the amount of pixels for a single em
 */
function getSingleEmInPixels() {
    let low = 0;
    let high = 200;
    let emWidth = Math.round((high - low) / 2) + low;
    const time = performance.now();
    let iters = 0;
    const maxIters = 10;
    while (high - low > 1) {
        const match = window.matchMedia(`(min-width: ${emWidth}em)`).matches;
        iters += 1;
        if (match) {
            low = emWidth;
        } else {
            high = emWidth;
        }
        emWidth = Math.round((high - low) / 2) + low;
        if (iters > maxIters) {
            console.warn(`max iterations reached ${iters}`);
            break;
        }
    }
    const singleEmPx = Math.ceil(window.innerWidth / emWidth);
    console.log(`window em width = ${emWidth}, time elapsed =  ${(performance.now() - time)}ms`);
    return singleEmPx;
}
1
Nadav Parag