Variable Font Weight
Pure CSS animation that smoothly slides a variable font's weight from 400 to 900 on hover — no script, a single element.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Text has 56 effects, including 4 free. Explore the category →
3 usage examples



How it works
The effect is entirely CSS-driven: the element's font-weight transitions from 400 to 900 on hover via a :hover rule, and the declaration transition: font-weight .3s interpolates that value continuously over 300 ms. The interpolation is smooth only when the loaded font is a variable font that supports the wght axis — Inter, specified here, covers values 100 to 900 without gaps.
On a static font or a system where Inter is not available, the browser substitutes sans-serif and the transition snaps to the nearest available weight with no smooth glide. The effect remains functional but loses its animation. No JavaScript is loaded or executed — the JS field in the code file is an empty string; the effect is 100% stylesheet.
Accessibility
- prefers-reduced-motion: not in the code. The transition runs regardless of the OS setting — for accessibility, add
@media (prefers-reduced-motion: reduce) { .text-variable-weight { transition: none } }. - The text element (
<span>) is a pure text node, fully readable by screen readers — noariaattributes are needed for this decorative effect. - The effect is triggered by
:hoveronly; no:focus-visiblestate is defined. On an interactive link or button, add a keyboard equivalent. - On touch devices,
:hoverdoes not fire on a simple tap — the animation stays invisible without a pointer device. - Text/background contrast depends entirely on the integration context — the effect defines neither text color nor background color.
Browser compatibility
Smooth weight interpolation requires a variable font with the wght axis and a browser supporting CSS transitions on font-weight.
If Inter is not available as a variable font, the transition snaps to the target weight without interpolation — no JS error, text stays readable.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="demo-preview">
<span class="demo-text text-variable-weight">Your text</span>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| font-weight (normal state) | 400 | Resting weight — use 100–300 for maximum contrast with the target. |
| font-weight (:hover state) | 900 | Target weight on hover — any integer the variable font supports (100–900). |
| transition: font-weight .3s | .3s ease | Animation duration and easing — .15s for a snappy pop, .6s ease-in-out for a cinematic glide. |
| font-family | Inter, sans-serif | Font in use — must be a variable font with a wght axis (Inter, Roboto Flex, Manrope, Source Sans 3…). |
| font-size | 2.5rem (inherited from .demo-text) | Text size — the effect is more visible at larger sizes. |
| letter-spacing | -.02em (inherited from .demo-text) | Tracking — adjust if the weight change shifts the text's optical rhythm. |
FAQ
wght axis. On a static font, the browser picks the nearest available weight and the transition snaps without a smooth glide. Inter loaded from Google Fonts (or installed as a system font) is variable and will interpolate correctly..text-variable-weight { font-weight: 400 } and .text-variable-weight:hover { font-weight: 900 }. Any integer pair is valid as long as the variable font supports those values. Examples: 100 → 800 for a dramatic effect, 400 → 600 for a UI-friendly subtlety.<span class="text-variable-weight">. Each span is self-contained — the :hover state is individual and no JS initialization is required.