Liqui Design
Handbook

Glass

What the material is, what it needs from your layout, and where it degrades.

Most liqui components are a LiquiGlass surface with a component-shaped content layer on top. Understanding the material is most of understanding the library — and knowing which components are deliberately not made of it is the rest.

The anatomy

A surface is four stacked layers plus your content:

LayerWhat it does
Backdrop Ablur() + saturate(). Never changes after first paint.
Backdrop BDisplacement only — backdrop-filter: url(#…), sampling A's output.
TintA gradient carrying legibility, scaled by frost.
SpecularA canvas-rendered rim light that makes the edge read as polished.
ContentYour children, above all of it.

Blur and displacement are on separate layers deliberately. While the filter's feImage decodes its map, Chromium treats an entire url(#f) blur() saturate() chain as inert — combined on one layer, even the base blur would pop in late. Split, the surface is frosted from the first frame and refraction fades in over it.

It needs something to refract

Loading…

Those are the three Button variants on a flat fill. The two solid ones look exactly as they do anywhere else. The glass one has gone slack — it is not broken, there is simply nothing behind it to bend. Glass is a lens; a lens over a solid colour shows you the solid colour.

Put surfaces over photography, video, a gradient with real edges, or content that scrolls underneath. If your design calls for glass on a flat background, you want material="clear" and a tint, not refraction.

Not everything is glass

The line the library draws is the one Apple draws, and it is not about which components are important enough to get the nice material:

Glass is for a surface you act through. A solid fill is for a control that carries a value.

Buttons, popups, menus, toolbars, sheets and dialogs are the first kind — they are the layer floating over your content, and letting that content through is what the material is for. Checkbox, Radio, Toggle and Switch are the second, and they are flat: --lq-control with a hairline at rest, --lq-accent when they are on.

Button sits on both sides of the line, which is why it is the clearest illustration of it. Its default variant is glass, because pressing a button does something. Its accent and danger variants are solid, because those say this is the one — and a tinted lens contradicts itself: the colour is the whole message, and the lens exists to let the wallpaper through it. Accent over a night photograph and accent over a bright one were two different colours.

This is also why a brand colour never needs frost tuning in liqui. Nothing carrying --lq-accent is a backdrop-filtered surface, so there is no transparency for a backdrop to leak through in the first place.

The dials

PropRangeWhat it controls
frost0–1Material density. 0 ≈ Apple's clear (needs a busy backdrop and its own dimming), 1 ≈ regular (adaptive frosted, safe anywhere). Default 0.35.
refractionpxfeDisplacementMap scale — how hard the rim bends.
bezelpxHow wide the refracting rim is. Menus want ~28, buttons ~11.
blurpxBase blur. frost adds up to 14px on top.
dispersion0+Chromatic aberration. Costs ~3× filter work — leave at 0 unless it's a hero surface.
specular0–1Rim light opacity.
radiuspxCorner radius. Also drives the displacement map's shape.
materialauto | frost | clearRendering tier. auto refracts where supported and frosts elsewhere.

Each of these is a per-surface prop, and the components set the geometric ones (radius, refraction, bezel) to values scaled to their own size. To move them all at once — or to change the colours — see Theming.

Performance budget

The expensive parts are the canvas-generated displacement map and the backdrop-filter chain, in that order.

  • Maps are cached module-wide, keyed by size + optics. Ten buttons of the same size cost one map.
  • Filters are hoisted into a single persistent hidden <svg> registry, so a remounted surface references an already-decoded filter and refracts on the first frame. This is why reopening a menu has no warm-up.
  • Generation is half-resolution above roughly 180×180.
  • dispersion > 0 triples the filter work. Reserve it.
  • Stacking many large backdrop-filter surfaces is the one thing that will actually cost you frames. Prefer one large surface over a dozen small ones.

Degradation

BrowserBehaviour
ChromiumFull refraction.
SafariDrops backdrop-filter entirely when it references an SVG filter. Falls back to frosted blur automatically. WebKit bug 245510 has an implementation in review.
FirefoxSame fallback.

The fallback is automatic — material="auto" detects support at module load. There is nothing to configure, but there is something to check: look at your UI in Safari. A design tuned to frost: 0 can be unreadable once refraction is gone, because in the refraction tier the lens was doing the work the tint would otherwise have to do.

Also honour user preference — a surface that ignores prefers-reduced-transparency is an accessibility bug, not a style choice:

@media (prefers-reduced-transparency: reduce) {
  .liqui-glass {
    --lq-tint: var(--fd-background);
    --lq-tint-deep: var(--fd-background);
  }
}

Two things that will bite you

Never measure a surface with getBoundingClientRect. Popups open under a scale() transition, and a rect measured mid-animation bakes a permanently undersized displacement map that nothing re-fires to correct. The result looks like weak frosted blur and is very hard to trace back. liqui uses ResizeObserver contentRect and offsetWidth, both of which are layout sizes and immune to transforms.

Never build the displacement map as an SVG data URI. Chromium rasterizes feImage SVG sources with CSS features disabled — mix-blend-mode and modern hsl() silently do nothing, corrupting the map into a full-surface smear. Generate it on a canvas.

Where to look next

Tuning these dials is mostly a matter of having seen enough of the material. liqui grew out of Liquid Glass Design, a growing gallery of liquid glass and glassmorphism references — interfaces, artwork and motion, each with the style prompt used to recreate it. It is the fastest way to work out what you are actually aiming at before you start moving frost and refraction around.

On this page