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.jsruntime — pointer specular highlight + press tightening; see "Dynamic fluidity" on this page).
Translucent bg + backdrop-filter blur + specular ring. Richer backdrops make the material pop.
Secondary text uses the token safe tier and stays legible over busy backdrops.
Usage
<link rel="stylesheet" href="https://unpkg.com/@oas-ui/theme@2/glass.css" />
<html data-glass>data-glassstacks on top ofdata-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, notnone—see Theming; if your build chain strips empty custom properties, use the identity filtersaturate(1)instead); - disabled under the
high-contrasttheme (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.
<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 underprefers-reduced-motion: reduce; not enabled for coarse pointers (touch); disabled underhigh-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 inglass.css); - The highlight layer sits above the surface background and below the label text (
isolation: isolate+ negativez-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 thumbdata-custom-thumb), and the press ring is only visible while pressed without moving.