PRACTICAL GUIDES · 8 MIN READ

From a live website to typography design tokens

Audit the fonts, sizes and weights a live site really uses, consolidate them into a scale, and write them down as CSS variables and design tokens.

Typography tokens are named values for font family, size, weight, line height and letter spacing. To derive them from a live site, list every family, size and weight actually in use, merge near-duplicates into a small scale, name the values in two layers (primitive and semantic), and publish them as CSS custom properties or as a JSON file in the Design Tokens Community Group format.

What typography tokens are

Most sites that have been alive for a few years have the same problem. Nobody decided to use eleven font sizes. They accumulated: a 15px here, a 0.9rem there, a one-off 22px for a campaign page. The design looks slightly uneven and nobody can say why.

Design tokens are the fix. A token is a named design decision stored as data: a name, a value and a type. Instead of font-size: 18px scattered through the code, you have one value called something like font.size.body and everything refers to it. For typography, five properties do nearly all the work.

Token kindCSS propertyTypical values
Font familyfont-familyA family name plus its fallback stack
Font sizefont-sizeA short scale, for example 13, 16, 20, 25, 31, 39 px
Font weightfont-weightTwo to four weights, for example 400, 600, 700
Line heightline-heightUnitless ratios, for example 1.1, 1.3, 1.6
Letter spacingletter-spacingSmall adjustments, often negative for large headings

This guide walks the path from a site that already exists to a clean token file. It works for your own site before a redesign, and for a reference site whose typographic system you want to understand. Studying someone’s scale is fine. Their fonts still need a license, as font licensing explained sets out.

Step 1: audit what the site really uses

Start from the rendered page, not the stylesheet. A stylesheet tells you what was declared, including rules that no longer match anything. The rendered page tells you what visitors see.

The manual way

Open DevTools, select a text element, and read font-family, font-size, font-weight, line-height and letter-spacing in the Computed tab. Repeat for each kind of text. To speed it up, paste a short script into the Console that walks the page and counts combinations.

// Count every family / size / weight / line-height combination on the page
const counts = new Map();
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
while (walker.nextNode()) {
  const node = walker.currentNode;
  const chars = node.textContent.trim().length;
  if (!chars) continue;
  const cs = getComputedStyle(node.parentElement);
  const family = cs.fontFamily.split(",")[0].trim();
  const key = [family, cs.fontSize, cs.fontWeight, cs.lineHeight].join(" | ");
  counts.set(key, (counts.get(key) || 0) + chars);
}
console.table([...counts].sort((a, b) => b[1] - a[1]));
A rough audit: each row is a style combination, ranked by how many characters use it.

The script is honest about its limits. It reports the first declared family, not the font actually rendered, it includes hidden text, and it does not look inside iframes. For a quick inventory it is good enough.

The faster way

Font Inspector’s Fonts on this page panel does this audit in one step. It lists every family on the page, ranked by share of text, with the weights and sizes each one appears in and a warning where a fallback is showing. Hover a family to outline where it is used, and click through to inspect any of them. On very large pages the scan is partial, and the panel says so.

Fonts on this page panel listing font families ranked by share of text, with the weights and sizes used and a fallback warning
The audit view: families ranked by share of text, with the weights and sizes in use.

Check more than the home page. Audit one page of each template: an article, a product or pricing page, a form, the footer. The guide to seeing every font on a page covers the panel in detail, and the website font checker gives a quick first look at a URL without installing anything.

Audit first, tokenize second.

Font Inspector lists every family, weight and size a page uses, saves them to a local library, and exports the result as CSS variables or design tokens. Free, no account.

Add to Chrome

Step 2: consolidate near-duplicates into a scale

Your audit will contain values that are obviously the same decision made twice. 15px and 16px body text. Weights 500 and 600 used interchangeably for emphasis. Line heights of 1.5, 1.55 and 1.6. The job now is to merge them.

  1. Sort the sizes from small to large and mark how much text uses each. The heavily used values are your anchors.
  2. Merge any two sizes that sit within a pixel or two of each other, unless they serve clearly different roles.
  3. Compare what is left with a modular scale. Pick a base, usually the body size, and a ratio, then see which audited sizes land near the steps. The type scale calculator makes this a thirty-second experiment.
  4. Snap the survivors to the scale. Aim for six to eight sizes in total.
  5. Do the same for weights and line heights. Most interfaces need a regular, one emphasis weight and one heading weight, plus a tight line height for headings and a relaxed one for body text.

Expect small visual changes when you snap values. That is the point: fewer, more deliberate steps. The reasoning behind ratios and steps is in how to build a typography scale. If you store sizes in rem, the px to rem converter saves arithmetic, and rem vs em vs px explains why rem is the usual choice for font sizes.

Step 3: name them in two layers

Naming is where token systems succeed or fail. The pattern that holds up is two layers.

  • Primitive tokens describe the raw options and say nothing about use: font.size.300, font.weight.semibold, font.family.serif. This is your palette.
  • Semantic tokens describe a role and point at a primitive: text.body.size, text.heading.weight. Components use only these.

The split pays off on the day the design changes. If body text moves up one step, you repoint one semantic token and leave everything else alone. A few naming habits help:

  • Use a numeric or t-shirt scale for primitives (100 to 900, or sm, md, lg). Leave gaps so you can add a step later.
  • Never put the value in the name. font-size-18 becomes a lie the first time it changes.
  • Name semantic tokens after the role, not the element. text.caption survives a markup change. text.figcaption does not.

Step 4: write them as CSS custom properties

For many projects, CSS custom properties are the whole token system. They need no build step and every browser understands them.

:root {
  /* Primitives */
  --font-family-sans: "Inter", system-ui, sans-serif;
  --font-family-serif: "Source Serif 4", Georgia, serif;

  --font-size-100: 0.8rem;   /* 12.8px */
  --font-size-200: 1rem;     /* 16px */
  --font-size-300: 1.25rem;  /* 20px */
  --font-size-400: 1.563rem; /* 25px */
  --font-size-500: 1.953rem; /* 31px */
  --font-size-600: 2.441rem; /* 39px */

  --font-weight-regular: 400;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;

  --line-height-tight: 1.15;
  --line-height-normal: 1.6;

  --letter-spacing-tight: -0.02em;
  --letter-spacing-normal: 0;

  /* Semantic */
  --text-body-family: var(--font-family-serif);
  --text-body-size: var(--font-size-200);
  --text-body-line-height: var(--line-height-normal);
  --text-heading-family: var(--font-family-sans);
  --text-heading-weight: var(--font-weight-bold);
  --text-heading-line-height: var(--line-height-tight);
}

body {
  font-family: var(--text-body-family);
  font-size: var(--text-body-size);
  line-height: var(--text-body-line-height);
}

h1 {
  font-family: var(--text-heading-family);
  font-size: var(--font-size-600);
  font-weight: var(--text-heading-weight);
  line-height: var(--text-heading-line-height);
  letter-spacing: var(--letter-spacing-tight);
}
A 1.25 scale on a 16px base, with primitives on top and semantic tokens pointing at them.

If you inspected a single style you want to reproduce, Font Inspector can copy it as CSS, Tailwind classes or SCSS variables, which is covered in copy typography as CSS or Tailwind. For a whole set, the library exports as CSS variables.

Step 5: the Design Tokens Community Group format

When tokens have to feed more than one platform, or travel between a design tool and code, JSON is the better home. The W3C Design Tokens Community Group publishes a format for exactly this. Its first stable version, 2025.10, was published in October 2025. The essentials:

  • A token is an object with a $value. $type says what kind of value it is, and $description is optional. Groups are plain nested objects, and a $type set on a group applies to the tokens inside it.
  • Typography-related types include fontFamily (a string or an array of names), fontWeight (a number from 1 to 1000 or a named alias such as "bold"), dimension and number.
  • A dimension is an object with a numeric value and a unit, and the unit must be px or rem. It is not a string such as "16px".
  • The composite typography type bundles fontFamily, fontSize, fontWeight, letterSpacing and lineHeight. lineHeight is a plain number that multiplies the font size.
  • A reference to another token is written in curly braces: "{font.size.200}".
  • Recommended file extensions are .tokens and .tokens.json.
{
  "font": {
    "family": {
      "$type": "fontFamily",
      "sans": { "$value": ["Inter", "system-ui", "sans-serif"] },
      "serif": { "$value": ["Source Serif 4", "Georgia", "serif"] }
    },
    "size": {
      "$type": "dimension",
      "200": { "$value": { "value": 1, "unit": "rem" } },
      "600": { "$value": { "value": 2.441, "unit": "rem" } }
    },
    "weight": {
      "$type": "fontWeight",
      "regular": { "$value": 400 },
      "bold": { "$value": 700 }
    }
  },
  "text": {
    "body": {
      "$type": "typography",
      "$description": "Long-form reading text",
      "$value": {
        "fontFamily": "{font.family.serif}",
        "fontSize": "{font.size.200}",
        "fontWeight": "{font.weight.regular}",
        "letterSpacing": { "value": 0, "unit": "px" },
        "lineHeight": 1.6
      }
    },
    "heading": {
      "$type": "typography",
      "$value": {
        "fontFamily": "{font.family.sans}",
        "fontSize": "{font.size.600}",
        "fontWeight": "{font.weight.bold}",
        "letterSpacing": { "value": -0.5, "unit": "px" },
        "lineHeight": 1.15
      }
    }
  }
}
Primitive and semantic typography tokens in the Design Tokens Format Module 2025.10 syntax.
Letter spacing in em In CSS, letter-spacing is usually written in em so that it scales with the text. The token format’s dimension type only allows px and rem, so convert the value for each size, or keep em-based tracking in your CSS layer. The letter spacing converter does the conversion.

Step 6: put the tokens to work

A token file earns its keep when tools read it. Style Dictionary is the common open source choice: it takes token files and generates CSS variables, SCSS, JavaScript, iOS and Android resources from the same source, and it supports the Design Tokens Community Group format. Tailwind CSS can consume the result too. In Tailwind 4 the theme is defined with CSS variables inside an @theme block, using namespaces such as --font-* for families, --text-* for sizes, --font-weight-*, --leading-* and --tracking-*, so a generated variables file maps across neatly.

Font Inspector’s library exports as JSON, CSS variables or design tokens. Treat any export as the raw material: it records what the site uses today, duplicates included. The consolidation and naming in steps 2 and 3 are judgment calls that still belong to you. Check the exported file against the format your pipeline expects before wiring it in.

Finally, test the tokens where the audit began. Apply them to each template and look at the pages side by side with the originals. If a page looks worse, you merged two values that were different on purpose. Split them again, give each a semantic name that explains the difference, and move on.

Questions & answers

What are typography design tokens?+

They are named, reusable values for font family, font size, font weight, line height and letter spacing. Components refer to the names, so a change to one token updates the whole product.

How do I find all the font sizes a website uses?+

Inspect each kind of text in the DevTools Computed tab, run a Console script that counts computed styles, or open Fonts on this page in Font Inspector, which lists every family with its weights and sizes.

What is the difference between primitive and semantic tokens?+

Primitive tokens name raw values, such as font.size.300. Semantic tokens name a role, such as text.body.size, and point to a primitive. Components should use semantic tokens only.

What does a typography token look like in the W3C design tokens format?+

It is an object with $type set to typography and a $value holding fontFamily, fontSize, fontWeight, letterSpacing and lineHeight. Sizes are dimension objects with a value and a unit of px or rem.

Should typography tokens use px or rem?+

Use rem for font sizes so text respects the reader’s browser font size setting. The design tokens format accepts both px and rem for dimensions.

Related free tools: Type scale calculator · PX to REM converter · Letter spacing converter

See it on real sites: What font does Airbnb use? · What font does GitHub use? · What font does Notion use? · What font does Spotify use?

Sources and further reading: Design Tokens Community Group: Design Tokens Format Module 2025.10 · MDN: Using CSS custom properties (variables) · Style Dictionary · Tailwind CSS: Theme variables

How to see every font a web page uses

List every font on a web page with the Network panel, Firefox’s Fonts tab, a short console snippet or one click, and learn how to read the result.

Build a typography scale that feels like a system

Build a type scale: pick a base size and a ratio, compute the steps in rem, make headings fluid with clamp(), and ship it as CSS or Tailwind tokens.

Copy any website’s typography as CSS, Tailwind or SCSS

Read a text style from any website with DevTools, clean it up, and rewrite it as portable CSS, Tailwind classes or SCSS variables. Or copy it in one click.