Glass

A liquid / frosted glass surface. <r-glass> frosts and refracts whatever sits behind it: backdrop-filter blur + saturate for the frost, an SVG feDisplacementMap for the liquid light-bending, plus a specular rim and highlight for the glass read. Everything is token-driven; content goes in the default slot.

Use when you want a translucent panel over rich, colorful content (a hero card, a floating toolbar, a media overlay). The displace attribute sets how liquid it looks (0 is a flat frosted pane). All effects degrade to a plain translucent surface where backdrop-filter is unsupported.

Playground

Drag the glass around the stage, adjust every attribute, and copy the exact markup. The default parameters are the iOS frosted-material look.

Frosted panel
drag me · tune the knobs
<r-glass blur="16" saturate="180" displace="8" radius="24">
  …
</r-glass>
<r-glass displace="8">
  <div class="panel">…</div>
</r-glass>

Place <r-glass> over colorful or busy content: the effect is invisible over a flat background.

Nesting

<r-glass> composes: nest one inside another for layered materials (e.g. a glass toolbar on a glass panel). Each layer refracts what's behind it.

Outer panel
Nested glass toolbar
<r-glass radius="26">
  <div class="panel">
    Outer panel
    <r-glass radius="16" displace="6">
      <div class="toolbar">Nested glass toolbar</div>
    </r-glass>
  </div>
</r-glass>

API Reference

Properties

Property Type Default Description
blur number 16 Backdrop blur radius, in px (the frost amount).
saturate number 180 Backdrop saturation, as a percentage: lifts the color of what's behind the glass.
displace number 8 Liquid refraction strength (SVG displacement scale). 0 is a flat frosted pane; higher = wavier.
frequency number 0.005 Turbulence base frequency: smaller values give larger, smoother ripples.
radius number 20 Corner radius, in px.
tint string subtle Glass fill tint: any CSS background value.
sheen boolean false Animated specular sweep across the surface.
interactive boolean false Hover lift + press-scale feedback, for clickable glass. Also makes the host a keyboard-operable button: role="button", a tab stop, Enter/Space act like a click.
rim boolean false Opt-in specular rim + chromatic edge for a more physically-lit look. WebGL first (always, synchronously), transparently upgraded to WebGPU in the background if available. Falls back to the plain CSS specular gradient when neither is available.

Refraction displace

displace drives the SVG feDisplacementMap scale: how strongly light bends through the surface. Set it to 0 for a plain frosted pane.

displace = 0
displace = 60
<r-glass displace="0">…flat frost…</r-glass> <r-glass displace="60">…liquid…</r-glass>

Sheen & interactive

sheen adds a moving specular highlight; interactive adds a hover lift and a springy press (using the shared --ran-motion-ease-spring token).

Hover & press me
<r-glass sheen interactive displace="36">
  <div>Hover &amp; press me</div>
</r-glass>

Rim — GPU specular edge (opt-in)

rim adds a second highlight layer: a specular rim lit from a fixed top-left light direction, plus a subtle chromatic (RGB) fringe at the panel's rounded-rect border. Unlike the displace refraction, it never samples the backdrop: the shader only knows the panel's own width/height/corner radius, so it costs none of the interactivity/accessibility tradeoffs a full backdrop-capturing GPU approach would (see Notes). It's a purely decorative layer on top of the same backdrop-filter frost; turning it on or off never changes what's behind the glass or how it's sampled.

Renders on WebGL first (synchronous, works in effectively every browser, so the rim never delays its own first paint) and transparently upgrades to WebGPU in the background if the browser has it (same effect, pixel-identical output). Falls back to the plain CSS specular gradient when neither GPU API is available (very old browsers, disabled, SSR); there's no broken/blank state to design around.

no rim
rim
<r-glass>…plain CSS specular…</r-glass> <r-glass rim>…GPU rim + chromatic edge (WebGL, upgrades to WebGPU)…</r-glass>

CSS parts & tokens

Style internals with ::part(glass), ::part(specular), and (when rim is set) ::part(rim), or override the --ran-glass-* custom properties:

Token Purpose
--ran-glass-blur Backdrop blur radius.
--ran-glass-saturate Backdrop saturation.
--ran-glass-radius Corner radius.
--ran-glass-tint Fill background.
--ran-glass-border Rim border.
--ran-glass-shadow Box shadow stack (specular + depth).
--ran-glass-specular-background Specular highlight background.
--ran-glass-specular-opacity Specular strength.
--ran-glass-reduced-transparency-background Fallback surface when the OS "reduce transparency" setting is on.
--ran-glass-reduced-transparency-shadow Fallback shadow in that same state.
r-glass::part(glass) {
  --ran-glass-tint: linear-gradient(135deg, rgba(0, 0, 0, 0.2), transparent);
}

Notes

  • Backdrop sampling. <r-glass> refracts the DOM behind it via backdrop-filter, so selectable text, live video, and interactive elements behind the glass keep working. rim (above) is a purely decorative GPU layer computed from the panel's own shape: it never samples the backdrop.
  • Legibility. Keep body text on a solid inner surface; don't rely on the glass alone for contrast.
  • Reduced transparency. <r-glass> responds to the OS-level "reduce transparency" / "increase contrast" setting (prefers-reduced-transparency: reduce): it swaps to a solid, theme-aware surface (--ran-color-bg-elevated by default) instead of frosting/refracting. Native controls do this automatically; this is the custom-element equivalent.
  • Cross-browser refraction. The feDisplacementMap liquid effect currently renders in Chromium only: Safari and Firefox drop that part of the backdrop-filter value and keep the blur/saturate/brightness frost, which is a legitimate (if flatter) fallback, not a broken state.
  • Motion. The surface only ever transitions transform (never color), so light/dark theme switches stay in one frame. Sheen and press respect prefers-reduced-motion.