Skip to content
← writing

A liquid-glass button, and the @property trick behind it

css
glassmorphism
@property
buttons

Petr Knoll's glass button has been making the rounds, and it's worth pulling apart, because almost every effect in it is a trick worth keeping. Hover and press it (it sits on a light, dotted panel so the frosting has something to blur):

The frost

The pill is translucent with a backdrop-filter: blur, so it genuinely frosts whatever sits behind it. That's the part that makes it read as glass and not just a light gradient, and it's why it needs a busy background to show off. Two inset shadows finish the edge: a soft dark one up top, a brighter one along the bottom, like light catching the lower rim.

.glass-btn {
  backdrop-filter: blur(clamp(1px, .125em, 4px));
  box-shadow:
    inset 0 .125em .125em rgba(0,0,0,.05),
    inset 0 -.125em .125em rgba(255,255,255,.5),
    0 .25em .125em -.125em rgba(0,0,0,.2);
}

The @property trick

Here's the clever bit. CSS won't animate the angle inside a gradient. The angle is part of an unparsed value, so the browser has nothing to interpolate. Registering the angle as a real typed custom property fixes that:

@property --glass-1 {
  syntax: "<angle>";
  inherits: false;
  initial-value: -75deg;
}

Now --glass-1 is an actual angle the browser can tween. The button's border is a conic-gradient(from var(--glass-1) …) masked down to a hairline with mask-composite: exclude, and a second registered angle drives a diagonal sheen that slides across the face. On hover and press, both angles transition, so the light appears to sweep around the glass instead of snapping.

The little touches

A separate blurred element under the button is the shadow, and it shifts as you interact, so the button feels like it lifts on hover. On :active the whole wrap tilts back with rotate3d(1, 0, 0, 25deg), a tiny bit of physicality that makes the press land. Everything is em-based, so it scales with font-size, and the angle animations quietly freeze on touch devices rather than jumping.

Full credit to Petr Knoll. Grab the component on the Liquid Glass Button page.

Ask your agent to implement this

Read the full writeup at https://seangeng.com/writing/a-liquid-glass-button.md and implement it in my project.

It covers: A liquid-glass button, and the @property trick behind it — Petr Knoll's frosted glass button, ported to a component. backdrop-filter for the frost, layered inset rims, and an animated conic-gradient border + sheen powered by @property angle interpolation.

Requirements:
- Follow the technique/approach exactly as described in the writeup.
- Adapt names, colors, and styling to my project's existing conventions.
- If it's a component, make it reusable with sensible props and TypeScript types.
- Keep it accessible: semantic HTML, keyboard support, and respect prefers-reduced-motion.
- When done, tell me which files you created or changed and how to use it.

Paste into Claude Code, Codex, Cursor, or any agent. view raw .md