Skip to content

Liquid Glass Gallery ​

A material layer of translucent surfaces, backdrop blur, and specular edge rings (edge refraction ships as a static displacement approximation; dynamic fluidity is provided by the optional glass-fluid.js runtime — pointer specular highlight + press tightening; see "Dynamic fluidity" on this page).

Open dialogShow message
PrimaryDefaultEdge refraction (static displacement approximation): control outlines bulge along the edge normal, center untouched
Card surface

Translucent bg + backdrop-filter blur + specular ring. Richer backdrops make the material pop.

Tag
Text legibility

Secondary text uses the token safe tier and stays legible over busy backdrops.

Usage ​

html
<link rel="stylesheet" href="https://unpkg.com/@oas-ui/theme@2/glass.css" />
<html data-glass>
  • data-glass stacks on top of data-theme / data-skin—freely composable;
  • the material needs backdrop contrast: it shines over colorful gradients/photos and recedes on flat same-hue backgrounds (text stays legible);
  • local opt-out: override --oas-glass-blur: none; --oas-glass-ring: transparent; --oas-glass-refraction: ; on any container (the refraction opt-out value must be empty, not none—see Theming; if your build chain strips empty custom properties, use the identity filter saturate(1) instead);
  • disabled under the high-contrast theme (solid accessibility tier wins).

Dynamic fluidity (pointer specular highlight, optional runtime) ​

The highlight needs a small runtime (glass-fluid.js): a single document pointermove listener resolves the surface via composedPath and writes the pointer position as element-local CSS variables; the runtime injects the highlight stylesheet into the matching components' shadow roots (adoptedStyleSheets), so no glass rule or marker exists in component sources (only --oas-glass-* variable consumption lines). Closing refraction while the app-bar overflow panel is open is done by a neutral in-component marker data-panel-open (so the panel is not clipped) and does not depend on the runtime — it works with glass.css alone or under reduced motion.

html
<link rel="stylesheet" href="https://unpkg.com/@oas-ui/theme@2/glass.css" />
<script type="module">
  import 'https://unpkg.com/@oas-ui/theme@2/glass-fluid.js'
</script>
<html data-glass>
  • Scope matches refraction (9 controls/nav/notification components: button / switch / slider thumb / app-bar / bottom-navigation / message / toast / snackbar / notification); content panels are excluded;
  • Guards: zero listeners without data-glass; disabled under prefers-reduced-motion: reduce; not enabled for coarse pointers (touch); disabled under high-contrast; starts/stops automatically as the markers or media queries change;
  • Tunable variables (CSS custom properties pierce shadow DOM): --oas-glass-px / --oas-glass-py (pointer-local coordinates written by the runtime — do not set manually), --oas-glass-sheen / --oas-glass-sheen-size / --oas-glass-sheen-press (sheen color, radius, pressed color; one step each for light and dark, defined in glass.css);
  • The highlight layer sits above the surface background and below the label text (isolation: isolate + negative z-index), so the specular reflection never washes out the label;
  • Scope and press: the hover sheen applies to all glass surfaces and buttons (including solid semantic/custom-color buttons — primary/success/warning/danger/has-color); for solid buttons the pressed state uses an edge inset ring (box-shadow inset, no fill lightening) — a white fill wash would push white-text contrast below the floor, while an edge ring leaves the label untouched (matching Apple's rim specular / Fluent's inset pressed cue); glass surfaces keep the stronger pressed sheen (a true enhancement);
  • Contrast gate: glass surfaces are gated at ≥60 on hover (composited over the theme page background — light #fff / dark #18181b) and ≥45 pressed; solid buttons at ≥45 on hover (transient large-text tier) with their resting/pressed baseline (no fill lightening) ≥60. For translucent surfaces over extreme host backdrops, ensuring text contrast is the host's responsibility; the switch's in-track label changes background with its checked state and is not part of this gate.
  • Boundary: with a still pointer, scrolling won't move the highlight until the pointer moves again; the slider thumb highlight is hidden in overlay states (dragging / focused / show-tooltip / custom thumb data-custom-thumb), and the press ring is only visible while pressed without moving.

Released under the MIT OR Apache-2.0 License.