Writing · 2026

Liquid Glass

Why glass

At WWDC25 Apple replaced the flat, blurred materials it had used since iOS 7 with Liquid Glass: a translucent material that “reflects and refracts its surroundings, while dynamically transforming to help bring greater focus to content.” (Apple Newsroom) The last part matters more than the optics. Glass is a tool for deciding where the eye goes.

The idea is a strict split into two layers. Content (photos, documents, messages) sits at the bottom and fills the screen. Controls and navigation form “a distinct functional layer” that floats above it. (HIG) Glass belongs only to the upper layer. Because it lets the content show through, the content stays the subject even under the toolbar; because it bends light at its rim, the control is still unmistakably a separate object you can touch.

That is the attention trade the whole system is built on. An opaque bar is always legible but claims a strip of the screen and a hard edge. A plain blur keeps the content but makes the control feel like a smudge. Glass is the middle: the control is present, readable, and visually quieter than the content, until you touch it.

The material as an object

Anatomy of the material

Apple's “Meet Liquid Glass” session breaks the material into layers. Lensing comes first: “where previous materials scattered light, this new set of materials dynamically bends, shapes, and concentrates light in real time.” Then highlights from light sources in the environment that respond to the geometry and, in places, to device motion. Then a shadow that is itself adaptive, darker over text and lighter over a flat, light background. Finally adaptivity: tint and dynamic range shift continuously so that what sits on the glass stays legible. (WWDC25 219)

The playground below implements each of these as a parameter. Drag the glass over the clock and across the waves of the macOS Tahoe wallpaper: the rim magnifies and compresses what is under it, the centre stays nearly undistorted, and a thin highlight runs around the edge facing the light. Switch the view to displacement field to see where the refraction actually happens, only in the bezel.

Playground · one glass shape over live contentdrag the glass
surface profile
surface profile
view
view
Cross-section · where the surface bends the light

A few things are worth trying. Set thickness to 0 and the shape collapses into an ordinary frosted rectangle; the rim is what makes it read as an object. Push ior above 2 and the edge starts to look like a cheap fisheye. Switch the profile to convex circle and the edge gets a hard crease where the dome meets the flat top; the squircle is smoother when the shape is stretched into a capsule, which is why most web implementations default to it.

parameterwhat it changesApple’s equivalent
thickness · iorHow far light bends at the rimLensing; larger glass simulates thicker material
bezel · profileWhere the bending happens and how sharp the edge looksThe curved edge of each control
frost blurHow much detail survives under the glassRegular blurs more, clear barely blurs
frost tint · adaptHow much the glass leans light or dark to keep glyphs legibleRegular adapts and flips; clear does not
tintA colour mapped onto the content brightness.tint(_:), only for the primary action
dispersionColour fringing where the bend is strongestNot named by Apple; a web-side touch
specular · light angleThe thin bright rim and its directionHighlights that respond to geometry and motion
shadowSeparation from what is belowAdaptive shadow, stronger over text
merge distanceHow close two shapes get before they melt togetherGlassEffectContainer(spacing:)
Deviation · a prism bends a beam
Layers · one mark, one step per sheet of glass

Regular, clear, tint

There are two variants and they should never be mixed. Regular “blurs and adjusts the luminosity of background content to maintain legibility”; most system components use it, and it is the right choice whenever the glass carries text. (HIG) Small regular elements such as tab bars even flip between a light and a dark appearance depending on what is behind them. Large ones (menus, sidebars) adapt but do not flip, because “their surface area is too big.” (WWDC25 219)

Clear is “permanently more transparent” and has no adaptive behaviour. Apple allows it only when three things are all true: the element sits on media-rich content, a dimming layer will not hurt that content, and what sits on the glass is bold and bright. (WWDC25 219) Over bright content the guidance is a dark dimming layer of 35% opacity. (HIG) In SwiftUI that is literally .glassEffect(.clear).background(.black.opacity(0.3)). (SwiftUI)

Drag the control across the seam below. The two halves are the same Tahoe wallpaper in its light and dark appearance. With regular, the glyph turns dark over the light one and light over the dark one, and the shadow strengthens where the waves are busiest. With clear, nothing adapts: the white star disappears against the bright half until you add the dimming layer.

Variants · regular adapts, clear does notdrag across the seam

Variant

Tint is not a fill. Selecting a colour “generates a range of tones that are mapped to content brightness underneath,” so the glass still changes with what is behind it; a solid fill “breaks the visual character of Liquid Glass.” (WWDC25 219) Tint is an attention device and is meant to be scarce: emphasise primary actions by colouring the background, not the symbol, and “refrain from adding color to the background of multiple controls.” (HIG)

Morphing: one surface, many shapes

The “liquid” half of the name is about continuity. “As you go between states in an app, Liquid Glass dynamically morphs between the controls in each context. This maintains the concept of having a singular floating plane.” (WWDC25 219) In code this is a GlassEffectContainer: glass shapes inside one container are rendered together, and “as shapes near one another, their paths start to blend into one another.” The container's spacing sets how near is near: “the higher the spacing, the sooner blending begins.” (SwiftUI)

On the web the same behaviour falls out of signed distance fields. Each shape is a function that returns the distance to its edge; a polynomial smooth minimum of two such functions grows a neck between them once they are closer than k. (Inigo Quilez) Because the refraction normal comes from the gradient of the merged field, the bend flows across the neck as if it were one piece of glass. Tap + to grow two tools out of the third, drag the drop into the toolbar, and turn on the distance field to see the merged shape.

GlassEffectContainer · shapes that share one surfacetap + · drag the drop
One surface, three shapes
The controls · the same material at the size you touch
glsl · shape and merge
// Signed distance to a rounded rectangle: < 0 inside, 0 on the edge.float sdRoundRect(vec2 p, vec2 halfSize, float r) {  vec2 q = abs(p) - halfSize + r;  return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;}​// Polynomial smooth-min (Inigo Quilez). k is the merge distance in px:// two shapes farther apart than k stay separate; closer, they grow a neck.float smin(float a, float b, float k) {  float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);  return mix(b, a, h) - k * h * (1.0 - h);}​float scene(vec2 p) {  float d = sdRoundRect(p - uCenter[0], uHalf[0], uRadius[0]);  for (int i = 1; i < N; i++)    d = smin(d, sdRoundRect(p - uCenter[i], uHalf[i], uRadius[i]), uK);  return d;}

Menus use the same idea at a larger scale. Buttons “fluidly morph into menus and popovers,” so the menu visibly comes from the control that summoned it and returns there when dismissed. (Apple) As glass grows it also changes character: it simulates “a thicker, more substantial material,” with deeper shadows, stronger lensing and softer scattering. (WWDC25 219) When there is no source to morph from, glass materializes: “instead of fading, Liquid Glass objects materialize in and out by gradually modulating the light bending and lensing.” (WWDC25 219) Compare the three below; the plain fade is the one that loses track of where the menu came from.

Menus · morph from the source, or materializetap ⋯
Transition

Touch: glass that answers back

At rest, glass is quiet. Under a finger it “responds to interaction by instantly flexing and energizing with light,” with “an inherent gel-like flexibility,” and “the material illuminates from within … starting right under your fingertips, the glow spreads throughout the element and onto any Liquid Glass elements nearby.” (WWDC25 219) In SwiftUI this is .interactive(), which makes glass react “by scaling, bouncing, and shimmering.” (WWDC25 323) Some controls only become glass while you use them: for sliders and toggles, “the knob transforms into Liquid Glass during interaction.” (Apple)

This is the second half of the attention design. Making the resting state quiet only works if the active state is unmistakable. Press the capsule below and drag: it swells, leans toward your finger with diminishing returns, glows from the touch point, and the glow reaches the small circle beside it. Drag the slider and its plain knob lifts into a glass lens over the track.

Interactive glass · flex, glow, liftpress and drag · slide the knob
js · springs
// Every motion in the demos is a spring, not a tween: it can be retargeted// mid-flight (tap + twice quickly) and it overshoots a little, like a gel.function step(s, dt) {  const a = -s.stiffness * (s.value - s.target) - s.damping * s.velocity;  s.velocity += a * dt;  s.value += s.velocity * dt;}​// Press: scale up, glow from the touch point, lean toward the finger.onPress(e)  { scale.target = 1.12; glow.target = 1; glowAt = point(e); }onMove(dx)  { lean.target = 60 * Math.tanh(dx / 120); }   // diminishing returnsonRelease() { scale.target = 1; glow.target = 0; lean.target = 0; }

Scrolling: get out of the way

Two behaviours exist purely to hand attention back to the content. When you scroll down, “tab bars shrink to bring focus to the content,” and “the moment users scroll back up, tab bars fluidly expand.” (Apple Newsroom) At the screen edges, a scroll edge effect replaces the old opaque bar background: it “gently dissolves the content into the background” and, over dark content, “intelligently switches to apply a subtle dimming instead.” (WWDC25 219) The HIG is explicit that these effects “aren't decorative. They don't block or darken like overlays,” and asks for one per view. (HIG)

Scroll inside the phone. The tab bar collapses to its active tab and expands again when you scroll up or tap it; the search button stays put. The top edge dissolves light cards into the paper and dims dark ones, and the account button and status bar flip their glyphs to match what is behind them. The hard style is the uniform band Apple uses with pinned headers.

Tab bar minimize · scroll edge effectscroll inside the phone

Scroll edge effect

App icons are a place where the same material reads as something else: a menu that grows out of the icon you are holding. Press and hold the Settings icon below. The icon lifts and swells, and the menu materializes from it rather than appearing beside it, which is what tells you which of the sixteen icons the menu belongs to. Let go or press Escape and it goes back.

Home screen · press and hold an iconhold the Settings icon

When glass should lead the eye

Every rule Apple gives about where to use the material is an attention rule. “Don't use Liquid Glass in the content layer”: a glass table view “would make it compete with other elements and muddy the hierarchy.” (HIG) (WWDC25 219) “Always avoid glass on glass”: when something sits on glass, give it fills and vibrancy instead. (WWDC25 219) “Use Liquid Glass effects sparingly … limit these effects to the most important functional elements in your app.” (HIG) And in steady states, such as launch, “avoid intersections between content and Liquid Glass.” (WWDC25 219)

The figure below puts the same wallpaper gallery under three treatments. The opaque bar is legible but hides a row and adds a hard edge. Glass on navigation only keeps the wallpapers as the subject, keeps the toolbar present but quiet, and lets a single tinted button announce the next step. Glass everywhere turns six captions into six competing lenses, and the toolbar no longer stands out because nothing does.

Hierarchy · where glass helps attention, and where it hurts

Treatment
where glass goes
  1. navigationTab bars, toolbars, sidebars, the controls that float over a scrolling document.use
  2. transientMenus, popovers, sheets and the knob of a slider while it is being dragged.use
  3. over mediaControls on a photo or video: clear glass plus a dimming layer, bold glyphs.clear only
  4. primary actionOne tinted button per view, so the next step is obvious.one
  5. contentList rows, cards, photos, article text, app backgrounds.don’t
  6. glass on glassA glass button inside a glass panel. Use fills and vibrancy for the top layer.don’t
  7. everythingMany custom glass controls on one screen. Each one costs attention and GPU time.don’t

Put together, the model is simple. Attention has three levels. Content is the default and gets no glass. Navigation is present, readable and quiet: regular glass, monochrome glyphs, adaptive shadow, out of the way when you scroll. The next step is loud only where it needs to be: one tint, one interactive response, one morph from the place you touched. Glass is useful exactly to the extent that it keeps those levels apart.

Building it on the web

People have rebuilt the effect in three ways. The SVG route computes a displacement map and applies it with feDisplacementMap. Chris Feijoo's write-up derives the map from a surface height function and Snell's law, sampling 127 points along one radius and reusing them around the shape. (kube.io) Shu Ding's snippet generates the map with a JavaScript “fragment shader” over a rounded-rectangle SDF (GitHub), which liquid-glass-react builds on, adding chromatic aberration by displacing each channel at a slightly different scale. (GitHub) Pup Atlas shows a lighter variant made of gradients, turbulence and inset shadows. (Atlas Pup Labs)

js · displacement map, after kube.io
// kube.io's approach for SVG: precompute the bend once, along one radius.const n1 = 1.0, n2 = 1.5;const squircle = x => Math.pow(1 - Math.pow(1 - x, 4), 0.25);​function profile(f, bezel, thickness, samples = 127) {  const out = [];  for (let i = 0; i < samples; i++) {    const x = i / (samples - 1), e = 0.001;    const slope = (f(Math.min(1, x + e)) - f(Math.max(0, x - e))) / (2 * e);    const theta1 = Math.atan(slope * thickness / bezel);     // angle of incidence    const theta2 = Math.asin((n1 / n2) * Math.sin(theta1));  // Snell    out.push(f(x) * thickness * Math.tan(theta1 - theta2));  // inward shift, px  }  return out;}// Then for every pixel: distance to the border -> magnitude from profile(),// border normal -> direction; write 128 + 127 * (dx, dy) / max into R and G.

The catch is support. backdrop-filter: url(#filter), which is what makes the SVG route refract the live page, works only in Chromium; Safari and Firefox limit backdrop-filter to the built-in functions. (LogRocket) The usual pattern is a blur-and-shadow base for everyone, with the refraction layered on after feature detection.

html · css + svg fallback
<svg width="0" height="0" aria-hidden="true">  <filter id="lg" color-interpolation-filters="sRGB">    <feImage href="data:image/png;base64,..." result="map"/>  <!-- the R/G map -->    <feDisplacementMap in="SourceGraphic" in2="map" scale="48"                       xChannelSelector="R" yChannelSelector="G"/>  </filter></svg>​<style>.glass {                                 /* every browser */  backdrop-filter: blur(4px) saturate(150%);  -webkit-backdrop-filter: blur(4px) saturate(150%);  box-shadow: inset 0 1px 0 rgb(255 255 255 / .55), 0 8px 24px rgb(0 0 0 / .14);}.chromium .glass {                       /* set from JS: only Chromium refracts */  backdrop-filter: url(#lg) blur(1px) saturate(150%);}</style>

The WebGL route trades live DOM for full control. You render the content into a texture and run a fragment shader that does everything per pixel. liquid-glass-js captures the page with html2canvas (GitHub); liquidGL ships its own rasteriser with a WebGPU-to-CSS fallback chain (GitHub); a Zenn tutorial walks through SDF, gradient normal, bezel curve, aberration and specular in about a hundred lines. (Zenn) The demos on this page take this route, and the shader is small enough to read in full. It works in every browser with WebGL; the cost is that the glass refracts a canvas, not arbitrary HTML.

glsl · refraction, dispersion, light
// Height of the glass across the bezel: t = 0 at the edge, 1 where it turns flat.float height(float t) {                       // convex squircle  t = clamp(t, 0.0, 1.0);  return pow(1.0 - pow(1.0 - t, 4.0), 0.25);}​void main() {  vec2 p = pixel();                           // css px, y down  float d = scene(p);  if (d > 0.0) { gl_FragColor = vec4(content(p), 1.0); return; }​  // 1. Normal. The SDF gradient points outward; the profile slope says how steep.  vec2 g = normalize(vec2(scene(p + vec2(1, 0)) - scene(p - vec2(1, 0)),                          scene(p + vec2(0, 1)) - scene(p - vec2(0, 1))));  float t = -d / uBezel;  float slope = (height(t + 0.01) - height(t - 0.01)) / 0.02;  vec3 N = normalize(vec3(g * uThickness * slope / uBezel, 1.0));​  // 2. Snell's law. A ray looking straight down enters glass with n = 1.5,  //    bends, and travels the local glass height before it hits the content.  vec3 R = refract(vec3(0, 0, -1), N, 1.0 / uIor);  vec2 offset = R.xy / -R.z * uThickness * height(t);​  // 3. Dispersion: red and blue bend by slightly different amounts.  vec3 c = vec3(frosted(p + offset * (1.0 + uCA)).r,                frosted(p + offset).g,                frosted(p + offset * (1.0 - uCA)).b);​  // 4. Light: a thin rim facing the light, a weaker one opposite, Schlick fresnel.  vec2 L = vec2(cos(uLight), sin(uLight));  float rim = exp(d / 1.4);  float spec = rim * (0.85 * max(dot(g, L), 0.0) + 0.38 * max(-dot(g, L), 0.0));  float fresnel = 0.04 + 0.96 * pow(1.0 - N.z, 5.0);  c += uSpecular * (spec + 0.18 * fresnel);​  gl_FragColor = vec4(c, 1.0);}

Three details carry most of the realism. First, refraction lives in the bezel only: the height profile is flat in the middle, so its slope, and therefore the bend, is zero there and steep near the edge. Second, the offset is not a fixed lens distortion; GLSL's refract applies Snell's law, so thickness and ior behave like their physical counterparts. Third, the rim highlight is thin (an exponential of the distance, about a pixel and a half wide) and lit from one direction. A broad white gradient is what makes most imitations look like plastic.

glsl · adaptivity and tint
// Regular glass leans light over light content and dark over dark content,// so whatever sits on it stays legible. Clear skips this step entirely.float L = luminance(frosted(p + offset));for (int i = 0; i < 4; i++) {                 // look a little around, not just under  float a = float(i) * 1.5708 + 0.6;  L += luminance(content(p + 44.0 * vec2(cos(a), sin(a)))) * 0.25;}vec3 frostColor = mix(vec3(0.06), vec3(1.0), smoothstep(0.22, 0.5, L * 0.5));c = mix(c, frostColor, uFrost);​// Tint maps a hue onto the content brightness instead of painting a flat fill.c = mix(c, uTint * (0.55 + 0.6 * luminance(c)), uTintAmount);

Adaptivity is a luminance sample. Regular glass looks a little around the pixel, not just under it, and leans its frost toward white or near-black; the demo also samples the content under each control on the CPU to choose the glyph colour and shadow strength, the same decisions Apple describes. Morphing is the smooth-min from earlier plus springs: every transition retargets a spring instead of running a fixed-length tween, so interrupting it never jumps.

On Apple platforms none of this is your job. The system components adopt the material automatically, and custom views get it from a handful of modifiers. (SwiftUI) (WWDC25 323) The design work is choosing where to put them.

swift · the native API
// SwiftUI (iOS 26+)Text("Hello").padding()    .glassEffect()                                    // .regular, capsule    .glassEffect(.regular.tint(.orange).interactive(), in: .rect(cornerRadius: 16))​Label("Flag", systemImage: "flag.fill").padding()    .glassEffect(.clear)    .background(.black.opacity(0.3))                  // clear needs a dimming layer​GlassEffectContainer(spacing: 40) {                   // shapes within 40pt melt together    HStack(spacing: 40) {        Image(systemName: "pencil").glassEffect().glassEffectID("pencil", in: ns)        if isExpanded {            Image(systemName: "eraser").glassEffect().glassEffectID("eraser", in: ns)        }    }}​Button("Done") {}.buttonStyle(.glassProminent)TabView { ... }.tabBarMinimizeBehavior(.onScrollDown)ScrollView { ... }.scrollEdgeEffectStyle(.hard, for: .top)

Accessibility and limits

Glass is only acceptable because it can be turned down. Reduce Transparency “makes Liquid Glass frostier and obscures more of the content behind it,” Increase Contrast makes elements “predominantly black or white” with a contrasting border, and Reduce Motion “disables any elastic properties.” (WWDC25 219) Apple has kept adding control since launch: iOS 26.1 added a tinted option (Apple Support), and iOS 27 adds a slider “from ultraclear to fully tinted,” alongside “more uniform refraction and improved contrast.” (Apple) The demos here follow prefers-reduced-motion (springs snap to their targets) and prefers-reduced-transparency (more blur, more frost), and every control is a real button, tab or range input with a label.

The demos are approximations. They refract a canvas (Apple's macOS Tahoe 26 and iOS 26 wallpapers inside Apple's iPhone 17 Pro bezel), not the page itself; the light is fixed rather than tied to device motion; the luminance sampling is a few taps, not Apple's adaptive tone mapping. Treat the code as a way to understand the material, and the guidelines as the part that actually transfers.

References

  1. Apple introduces a delightful and elegant new software design apple.com
  2. Materials | Human Interface Guidelines developer.apple.com
  3. Meet Liquid Glass — WWDC25 developer.apple.com
  4. Build a SwiftUI app with the new design — WWDC25 developer.apple.com
  5. Build a UIKit app with the new design — WWDC25 developer.apple.com
  6. Adopting Liquid Glass developer.apple.com
  7. Applying Liquid Glass to custom views developer.apple.com
  8. Glass.clear | SwiftUI developer.apple.com
  9. GlassEffectContainer | SwiftUI developer.apple.com
  10. Color | Human Interface Guidelines developer.apple.com
  11. Scroll views | Human Interface Guidelines developer.apple.com
  12. About iOS 26 Updates support.apple.com
  13. iOS 27 apple.com
  14. Liquid Glass in the Browser: Refraction with CSS and SVG kube.io
  15. Liquid Glass, but in CSS atlaspuplabs.com
  16. shuding/liquid-glass github.com
  17. rdev/liquid-glass-react github.com
  18. dashersw/liquid-glass-js github.com
  19. Liquid Glass refraction in WebGL (Zenn) github.com
  20. naughtyduk/liquidGL github.com
  21. How to create Liquid Glass effects with CSS and SVG blog.logrocket.com
  22. Smooth minimum — Inigo Quilez iquilezles.org
  23. macOS Tahoe 26’s Default Wallpaper (demo backgrounds, © Apple) 512pixels.net
  24. iOS 26 wallpapers, light and dark (demo backgrounds, © Apple) 9techeleven.com
  25. Hairline — isometric line figures that answer the pointer hairline.lucasmarkes.com
  26. lucasmarkes/hairline (MIT; the figures in this post are drawn on it) github.com
  27. Apple Design Resources — iPhone 17 Pro product bezel developer.apple.com