{
  "schemaVersion": 1,
  "slug": "font-size-em-px-calculator",
  "category": "everyday",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "7f8207b4fcb7ecf49228d8ac833c53ef8b66555126689568a6c28333551c1ca4",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/font-size-em-px-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "em = px ÷ (b × ep); rem = px ÷ b; px = em × b × ep = rem × b; px_i = b × r^i (i = 0 … steps − 1)",
    "vars": [
      [
        "px",
        "pixel size"
      ],
      [
        "b",
        "root font size in pixels"
      ],
      [
        "ep",
        "parent size as a multiple of the root"
      ],
      [
        "em",
        "size relative to the parent"
      ],
      [
        "rem",
        "size relative to the root"
      ],
      [
        "r",
        "type scale ratio"
      ],
      [
        "px_i",
        "scale step in pixels"
      ],
      [
        "steps",
        "number of scale steps"
      ]
    ],
    "note": "For font-size, em uses the inherited parent font size, while rem uses the root font size. With a 16 px root and a parent multiplier of 0.8, the parent is 12.8 px. Then 1.5 em = 19.2 px, while 1.5 rem = 24 px. Select em or rem to enter a relative size; select px for the reverse conversion."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-09",
    "sources": [
      {
        "name": "MDN — CSS length units: em and rem",
        "url": "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/length"
      }
    ]
  },
  "contract": {
    "compute": "const invalid={emValue:null,remValue:null,nestedEm:null,nestedPx:null,scale:'',note:'',__error:'inputError'};if(!['px','em','rem'].includes(sourceUnit)||!Number.isFinite(basePx)||basePx<1||basePx>100||!Number.isFinite(parentEm)||parentEm<0.1||parentEm>10)return invalid;const source=sourceUnit==='px'?pxValue:relativeValue;if(!Number.isFinite(source)||source<0||source>500)return invalid;const parentPx=basePx*parentEm;const px=sourceUnit==='em'?source*parentPx:sourceUnit==='rem'?source*basePx:source;const emValue=px/parentPx,remValue=px/basePx,nestedEm=remValue,nestedPx=px;const ratio=Number(scaleRatio)||1.25;const scale=[];for(let i=steps-1;i>=0;i--){const value=basePx*Math.pow(ratio,i);scale.push((i===0?'base ':i>0?'+':'')+i+': '+value.toFixed(2)+' px / '+(value/basePx).toFixed(3)+' rem');}return{emValue,remValue,nestedEm,nestedPx,scale:scale.join('  |  '),note:parentEm===1?'With a parent size of 1 em, em and rem are identical':'Nested em compounds through each parent — rem avoids that entirely'};",
    "inputs": [
      {
        "name": "sourceUnit",
        "type": "select",
        "default": "px",
        "options": [
          {
            "value": "px"
          },
          {
            "value": "em"
          },
          {
            "value": "rem"
          }
        ]
      },
      {
        "name": "basePx",
        "type": "number",
        "default": 16,
        "min": 1,
        "max": 100,
        "step": 0.5,
        "slider": true,
        "requiredValue": true,
        "strictRange": true
      },
      {
        "name": "pxValue",
        "type": "number",
        "default": 24,
        "min": 0,
        "max": 500,
        "step": "any",
        "showWhen": {
          "sourceUnit": [
            "px"
          ]
        },
        "requiredValue": true,
        "strictRange": true
      },
      {
        "name": "relativeValue",
        "type": "number",
        "default": 1.5,
        "min": 0,
        "max": 500,
        "step": "any",
        "requiredValue": true,
        "strictRange": true,
        "showWhen": {
          "sourceUnit": [
            "em",
            "rem"
          ]
        }
      },
      {
        "name": "parentEm",
        "type": "number",
        "default": 1,
        "min": 0.1,
        "max": 10,
        "step": 0.05,
        "slider": true,
        "requiredValue": true,
        "strictRange": true
      },
      {
        "name": "scaleRatio",
        "type": "select",
        "default": "1.25",
        "options": [
          {
            "value": "1.125"
          },
          {
            "value": "1.2"
          },
          {
            "value": "1.25"
          },
          {
            "value": "1.333"
          },
          {
            "value": "1.5"
          },
          {
            "value": "1.618"
          }
        ],
        "advanced": true
      },
      {
        "name": "steps",
        "type": "number",
        "default": 5,
        "min": 1,
        "max": 10,
        "step": 1,
        "advanced": true
      }
    ],
    "outputs": [
      {
        "name": "emValue",
        "precision": 4,
        "unit": "em"
      },
      {
        "name": "remValue",
        "precision": 4,
        "unit": "rem"
      },
      {
        "name": "nestedEm",
        "precision": 4,
        "unit": "em"
      },
      {
        "name": "nestedPx",
        "precision": 2,
        "unit": "px"
      },
      {
        "name": "scale",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "note",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
