web-dev-qa-db-ja.com

Javascriptでemをpxに変換(およびデフォルトのフォントサイズを取得)

em測定の正確なピクセル幅を取得すると便利な場合があります。たとえば、emsで測定されるCSSプロパティ(ボーダーやパディングなど)を持つ要素があり、ボーダーまたはパディングの正確なピクセル幅を取得する必要があるとします。このトピックに関する既存の質問があります:

JavaScriptまたはJQueryを使用してデフォルトのフォントサイズをピクセル単位で取得するにはどうすればよいですか

この質問は、デフォルトのフォントサイズの取得について尋ねています。これは、相対的なem値を正確なpx値に変換するために必要です。

この回答 は、要素のデフォルトのフォントサイズを取得する方法についてかなり良い説明があります。

Emは幅を測定するため、1000 emの長さのdivを作成し、client-Widthプロパティを1000で除算することにより、常に正確なピクセルフォントサイズを計算できます。ピクセル結果の誤った切り捨てを避けます。

したがって、この回答をガイドとして使用して、デフォルトのフォントサイズを取得するために次の関数を作成しました。

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

デフォルトのフォントサイズを取得したら、emsに要素のデフォルトのフォントサイズを掛けて結果を四捨五入するだけで、任意のem幅をpx幅に変換できます。

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

問題:getDefaultFontSizeは、デフォルトのフォントサイズを返す単純で副作用のない関数であることが理想的です。しかし、[〜#〜] does [〜#〜]には不幸な副作用があります:DOMを変更します!子を追加してから、子を削除します。有効なoffsetWidthプロパティを取得するには、子を追加する必要があります。子divをDOMに追加しない場合、要素がレンダリングされないため、offsetWidthプロパティは0のままです。子要素をすぐに削除しても、この関数は、親要素でリッスンしているイベント(Internet ExplorerのonpropertychangeやW3CのDOMSubtreeModifiedイベントなど)の起動など、意図しない副作用を引き起こす可能性があります。

質問:イベントハンドラを誤って起動したり、原因を引き起こしたりしない、本当に副作用のないgetDefaultFontSize()関数を記述する方法はありますか他の意図しない副作用?

51
Channel72

編集:いいえ、ありません。

DOMに影響を与えずに、指定された要素のレンダリングされたフォントサイズを取得するには:

parseFloat(getComputedStyle(parentElement).fontSize);

これは、 この質問 への答えに基づいています。


編集:

IEでは、parentElement.currentStyle["fontSize"]を使用する必要がありますが、サイズをpxに変換することは保証されません。それで終わりです。

さらに、このスニペットは要素のデフォルトのフォントサイズを取得するのではなく、その実際のフォントサイズを取得します。これは実際にクラスとスタイルが関連付けられている場合に重要ですそれと。つまり、要素のフォントサイズが2emの場合、2 emのピクセル数を取得します。フォントサイズがインラインで指定されていない限り、変換率を正しく取得することはできません。

26
mgiuffrida

より良い答えがあります。私のコードは、変数emのunit-pxに1em値を格納します。

  1. このdivをHTMLコードの任意の場所に配置します

    <div id="div" style="height:0;width:0;outline:none;border:none;padding:none;margin:none;"></div>
    
  2. JavaScriptファイルにこの関数を配置します

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

これで、この関数を呼び出すたびに'getValue'パラメータにそのテストdivのIDを使用すると、変数名emになります。これにはpxで1 emの値が含まれます。

7
Dhruv Singhal

素早い汚れが必要な場合(および要素ではなく、本体の基本フォントサイズに基づいて)、私は次のようにします:

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

次のソリューションでは、バイナリ検索とwindow.matchMediaを使用して、ウィンドウのem幅を見つけます。次に、ウィンドウのem幅をウィンドウのピクセル幅で除算して、最終結果を取得します。 DOMを使用せず、副作用なし!パフォーマンスの観点では、コンプで約0.2msで約8回の反復が必要です。

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