How to pull ready-to-paste font-variation-settings from any variable font
- Step 1Drop the variable font in — Upload TTF, OTF, WOFF, or WOFF2. WOFF and WOFF2 are decompressed in-browser, so the same file you ship to production is what gets read.
- Step 2Read the generated css_examples — The output's css_examples array holds one font-variation-settings line per named instance, each prefixed with a `/* InstanceName */` comment. This is the part most people copy directly.
- Step 3Pick the instance you need — Scan the comment labels for the style you want — Regular, Medium, Bold, Condensed, Display. Copy that block into a CSS rule that also declares the matching font-family.
- Step 4Set the matching font-family — font-variation-settings only affects a font that is already applied. Add the snippet to a selector with font-family pointing at the @font-face you loaded for this file.
- Step 5For fluid effects, use the reported axis range — If you want hover weight or fluid optical size rather than a fixed instance, read the axes table for min/default/max and write your own font-variation-settings value inside those bounds.
- Step 6Save the JSON for reference — Download `<fontname>.axes.json`. It bundles css_examples with the full axes and instances arrays, so your team always has both the ready-made snippets and the raw ranges.
What you copy versus what you write yourself
The tool generates instance snippets directly; for anything continuous you author the value using the reported range.
| You want | Source | How |
|---|---|---|
| A specific named style (Bold, Condensed) | css_examples | Copy the comment-labelled block verbatim |
| A weight between two named instances | axes (wght min/max) | Write "wght" N with N inside the range |
| Fluid optical size by viewport | axes (opsz min/max) | Interpolate "opsz" N within bounds, or use font-optical-sizing: auto |
| A custom axis effect (GRAD, etc.) | axes (custom tag) | Write "TAG" N; no CSS shorthand exists for custom axes |
| All axes of a multi-axis instance | instances[].coordinates | Copy the full block — leaving an axis out reverts it to default |
Mapping axes to CSS shorthands
Registered axes have CSS shorthands; the generator gives you the explicit font-variation-settings form, which always works. Shorthands are equivalent for the registered axes only.
| Axis | Explicit (always works) | Registered shorthand |
|---|---|---|
| wght | font-variation-settings: "wght" 600 | font-weight: 600 |
| wdth | font-variation-settings: "wdth" 75 | font-stretch: 75% |
| ital | font-variation-settings: "ital" 1 | font-style: italic |
| slnt | font-variation-settings: "slnt" -10 | font-style: oblique -10deg |
| opsz | font-variation-settings: "opsz" 28 | font-optical-sizing: auto |
| custom (GRAD...) | font-variation-settings: "GRAD" 88 | none |
Cookbook
Paste-ready patterns. Replace the family name with your @font-face family; use the exact instance snippets the tool generated for your file.
Drop a named instance into a class
ExampleThe generated snippet is already correct for the file. Add it to a rule with the right font-family and you are done.
/* generated css_examples entry, instance "Bold" */
.btn--strong {
font-family: "Acme Variable";
font-variation-settings: "wght" 700;
}Multi-axis instance copied whole
ExampleA condensed display style sets several axes at once. Copying the full generated block keeps width and optical size correct; copying only wght would silently revert the others.
/* instance "Condensed Display" */
.hero {
font-family: "Acme Variable";
font-variation-settings: "wght" 800, "wdth" 75, "opsz" 72;
}Fluid weight using the reported range
ExampleFor an interactive weight rather than a fixed instance, take the axis min/max from the report and animate within it. Stay inside the bounds or the browser clamps.
/* axes: wght min 200, max 800 */
.menu a { font-variation-settings: "wght" 400; transition: font-variation-settings .15s; }
.menu a:hover { font-variation-settings: "wght" 700; } /* both inside 200-800 */Optical size that tracks the type size
ExampleIf the report lists opsz, you can let the browser interpolate it automatically by font-size, or pin it for a specific context like fine print.
/* axes lists opsz 14-72 */
body { font-optical-sizing: auto; }
.legal { font-variation-settings: "opsz" 14; } /* pin small-text design */Wire a custom parametric axis
ExampleCustom axes have no CSS shorthand, so the explicit font-variation-settings form is the only way. The generator/axes report gives you the exact tag and range.
/* axes: GRAD min -50, default 0, max 100 */
.dark-mode .card {
font-variation-settings: "wght" 400, "GRAD" 60; /* heavier strokes, same width */
}Edge cases and what actually happens
Every row below was probed against the live API. Some documented requirements (alphabetical axis order, numerical tuple order) are not actually enforced in practice — useful to know if you've been blaming the wrong thing for a 400.
css_examples comes back empty
Expected — no named instancesThe generator builds one block per named instance. A font with axes but no named instances yields an empty css_examples array. That is not a failure — read the axes table and author your own font-variation-settings from the min/default/max.
You set wght but width snaps back to normal
Gotcha — settings resetfont-variation-settings is not additive: declaring it overrides all previously set axes for that element. If an instance sets wght and wdth, you must copy the whole block. The generator emits the full multi-axis line precisely so you copy all of it.
Your weight value renders at the boundary
Gotcha — clampedA value outside the axis's reported min/max is clamped by the browser, so "wght" 900 on a font whose max is 700 renders at 700 with no error. Always keep authored values inside the ranges the tool reports.
Static font uploaded
Error — no variable axesA non-variable font has no axes to generate from, so the tool throws "This font has no variable axes (no fvar table or empty axis list)." To produce @font-face CSS for a static font, use the Font Face Generator instead.
Instance labels are generic (Instance 2, ...)
Expected — name fallbackSnippet comment labels use the instance's name, which is resolved from Windows-English name records. If a name is missing there, the label is Instance N. The font-variation-settings values inside are still correct — only the comment is generic.
A custom axis has no shorthand
By design — explicit onlyOnly the five registered axes have CSS shorthands (font-weight, font-stretch, font-style, font-optical-sizing). For custom tags like GRAD or MONO, font-variation-settings is the only route — which is exactly the form this tool emits.
A decimal value like 87.5 appears in a snippet
Expected — Fixed 16.16fvar stores coordinates in Fixed 16.16, so instances can sit at fractional axis values. The generator decodes and writes them verbatim. Keep the decimal — rounding to 88 may land on a slightly different design point.
Snippet has no effect on the page
Gotcha — font not appliedfont-variation-settings only affects the variable font that is actually applied to the element. If the selector's font-family does not resolve to the loaded variable face (typo, fallback in effect, file not loaded), the settings are ignored. Confirm the @font-face loads first.
You expected font-named-instance shorthand
Not generated — settings form onlyThe tool generates the explicit font-variation-settings form, which has the broadest support. The newer font-named-instance / font-variant-alternates approaches are not emitted. The explicit form covers every axis, registered or custom.
Frequently asked questions
Where do the CSS snippets come from?
From the font's named instances. The tool reads each named instance's coordinates from the fvar table and writes a font-variation-settings block from them, labelled with the instance name as a comment. There is one block per named instance.
Why is the snippet list empty for my font?
Because the font declares axes but no named instances — there is nothing to template. Use the axes table to read each axis's min/default/max and author your own font-variation-settings value.
Do I need to set font-family too?
Yes. font-variation-settings only affects a variable font that is already applied. Put the snippet on a selector whose font-family resolves to the @font-face you loaded for this file, or it does nothing.
Why does setting width reset the weight?
font-variation-settings replaces the whole set of axis values for that element; it is not additive. To keep multiple axes, set them all in one declaration. That is why the tool emits the full multi-axis line per instance. To bake one instance into a static file instead, use the Variable Font Freezer.
What if I want a weight between two named styles?
Read the wght axis min/max from the report and write your own "wght" value inside that range. Variable fonts are continuous, so any value in range is valid — but values outside the range are clamped to the boundary.
Can I use the registered shorthands instead?
Yes, for the five registered axes (font-weight, font-stretch, font-style, font-optical-sizing). The tool gives you the explicit font-variation-settings form, which always works and is the only option for custom axes.
How do I target a custom axis like GRAD?
With font-variation-settings: "GRAD" N, using the tag and range the report shows. Custom axes have no CSS shorthand, so this explicit form is the only way to reach them.
Why is an axis value a decimal?
fvar values are Fixed 16.16 fixed-point. The tool decodes them by dividing by 65536, so fractional coordinates (common on width and parametric axes) appear exactly. Keep the decimal in your CSS.
Does this generate @font-face blocks?
No — it generates font-variation-settings blocks per instance plus the axis ranges. For full @font-face declarations that bind weights to one file, use the Font Face Generator; for CSS custom properties, the CSS Variable Generator.
Is the font uploaded to generate the CSS?
No. The fvar table is parsed in your browser and the snippets are built locally. The font binary never leaves the page, so you can use it on unreleased or licensed fonts safely.
Why does my snippet have no visible effect?
Either the font-family does not resolve to the loaded variable font, or your value is outside the axis range and got clamped to a value near the default. Confirm the @font-face loads and that your value sits within the reported min/max.
What formats can I drop in?
TTF, OTF, WOFF, and WOFF2. Compressed web formats are decompressed in-browser before parsing. TrueType Collections (.ttc) are not supported.
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.