Skip to content

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 premium translucent panel over rich content — a hero card, a floating toolbar, a media overlay. The displace knob 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, tune every knob, and copy the exact markup. The default parameters are the iOS frosted-material look.

<r-glass displace="8">
  <div class="panel">…</div>
</r-glass>
html
<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
html
<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

PropertyTypeDefaultDescription
blurnumber16Backdrop blur radius, in px (the frost amount).
saturatenumber180Backdrop saturation, as a percentage — lifts the color of what's behind the glass.
displacenumber8Liquid refraction strength (SVG displacement scale). 0 is a flat frosted pane; higher = wavier.
frequencynumber0.005Turbulence base frequency — smaller values give larger, smoother ripples.
radiusnumber20Corner radius, in px.
tintstringsubtleGlass fill tint — any CSS background value.
sheenbooleanfalseAnimated specular sweep across the surface.
interactivebooleanfalseHover 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.
rimbooleanfalseOpt-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
html
<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
html
<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
html
<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:

TokenPurpose
--ran-glass-blurBackdrop blur radius.
--ran-glass-saturateBackdrop saturation.
--ran-glass-radiusCorner radius.
--ran-glass-tintFill background.
--ran-glass-borderRim border.
--ran-glass-shadowBox shadow stack (specular + depth).
--ran-glass-specular-backgroundSpecular highlight background.
--ran-glass-specular-opacitySpecular strength.
--ran-glass-reduced-transparency-backgroundFallback surface when the OS "reduce transparency" setting is on.
--ran-glass-reduced-transparency-shadowFallback shadow in that same state.
css
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.

Released under the MIT License.