My attempt to Clone Liquid Glass in the Web
Explore how to recreate Apple's stunning Liquid Glass effect using CSS, SVG Displacement Maps, and refraction calculations.
Introduction
Apple introduced the Liquid Glass effect during WWDC 2025 in June—a stunning UI effect that makes interface elements appear to be made of curved, refractive glass. This article is a hands-on exploration of how to recreate a similar effect on the web using CSS, SVG displacement maps, and physics-based refraction calculations.
Instead of chasing pixel-perfect parity, we'll approximate Liquid Glass, recreating the core refraction and a specular highlight, as a focused proof-of-concept you can extend.
Chrome-only demo
The interactive demo at the end currently works in Chrome only (due to SVG filters as backdrop-filter).
You can still read the article and interact with the inline simulations in other browsers.
Understanding Refraction
Refraction is what happens when light changes direction as it passes from one material to another (like from air into glass). This bending occurs because light travels at different speeds through different materials.
The relationship between the incoming and outgoing light angles is described by Snell-Descartes law:
Where:
- = refractive index of first medium
- = angle of incidence
- = refractive index of second medium
- = angle of refraction
Key observations:
- When , the light ray passes straight through without bending.
- When , the ray bends toward the normal (perpendicular line to the surface).
- When , the ray bends away from the normal (Total Internal Reflection).
- When incident ray is orthogonal to the surface, it passes straight through regardless of refractive indices.
Limitations in this project
To keep things focused we avoid complex branches of behavior:
- Ambient medium has (air).
- Use materials with , preferably (glass).
- Only one refraction event (ignore any later exit/second refraction).
- Incident rays are always orthogonal to the background plane (no perspective).
- Objects are 2D shapes parallel to the background (no perspective).
- No gap between objects and background plane (only one refraction).
- Circle shapes only in this article:
- Extending to other shapes requires preliminary calculations.
- Circles let us form rounded rectangles by stretching the middle.
Under these assumptions every ray we manipulate has a well-defined refracted direction via Snell's Law, and we simplify a lot our calculations.
Creating the Glass Surface
To create our glass effect, we need to define the shape of our virtual glass surface. Think of this like describing the cross-section of a lens or curved glass panel.
Surface Function
Our glass surface is described by a mathematical function that defines how thick the glass is at any point from its edge to the end of the bezel:
const height = f(distanceFromSide);From the height we can calculate the angle of incidence, which is the angle between the incoming ray and the normal to the surface at that point. The normal is simply the derivative of the height function at that point, rotated by degrees:
const delta = 0.001;
const y1 = f(distanceFromSide - delta);
const y2 = f(distanceFromSide + delta);
const derivative = (y2 - y1) / (2 * delta);
const normal = { x: -derivative, y: 1 };Surface Equations
For this article, we will use four different height functions to demonstrate the effect of the surface shape on the refraction:
Simple circular arc → a spherical dome. Easier than the squircle, but the transition to the flat interior is harsher, producing sharper refraction edges—more noticeable when the shape is stretched away from a true circle.
Uses the Squircle Apple favors: a softer flat→curve transition that keeps refraction gradients smooth even when stretched into rectangles—no harsh interior edges. It also makes the bezel appear optically thinner than its physical size because the flatter outer zones bend light less.
The concave surface is the complement of the convex function, creating a bowl-like depression. This surface causes light rays to diverge outward, displacing them beyond the glass boundaries.
We could make the surface function more complex by adding more parameters, but these four already give a good idea of how the surface shape affects the refraction.
Simulation
Now let's see these surface functions in action through interactive ray tracing simulations. The following visualization demonstrates how light rays behave differently as they pass through each surface type, helping us understand the practical implications of our mathematical choices.
From the simulation, we can see that concave surfaces push rays outside the glass; convex surfaces keep them inside.
We want to avoid outside displacement because it requires sampling background beyond the object. Apple’s Liquid Glass appears to favor convex profiles (except for the Switch component, covered later).
The background arrow indicates displacement—how far a ray lands compared to where it would have landed without glass. Color encodes magnitude (longer → more purple).
Take a look at symmetry: rays at the same distance from the border share the same displacement magnitude on each side. Compute once, reuse around the bezel/object.
Displacement Vector Field
Now that calculated the displacement at a distance from border, let's calculate the displacement vector field for the entire glass surface.
The vector field describes at every position on the glass surface how much the light ray is displaced from its original position, and in which direction. In a circle, this displacement is always orthogonal to the border.
Pre-calculating the displacement magnitude
Because we saw that this displacement magnitude is symmetric around the bezel, we can pre-calculate it for a range of distances from the border, on a single radius.
This allows us to calculate everything in two dimensions once (x and z axis), on one "half-slice" of the object, and we will the rotate these pre-calculated displacements around the z-axis.
The actual number of samples we need to do on a radius is of 127 ray simulations, and is determined by the constraints of the SVG Displacement Map resolution. (See next section.)
Normalizing vectors
In the above diagram, the arrows are all scaled down for visibility, so they do not overlap. This is normalization, and is also useful from a technical standpoint.
To use these vectors in a displacement map, we need to normalize them. Normalization means scaling the vectors so that their maximum magnitude is , which allows us to represent them in a fixed range.
So we calculate the maximum displacement magnitude in our pre-calculated array:
const maximumDisplacement = Math.max(...displacementMagnitudes);And we divide each vector's magnitude by this maximum:
displacementVector_normalized = {
angle: normalAtBorder,
magnitude: magnitude / maximumDisplacement,
};We store maximumDisplacement as we will need it to re-scale the displacement map back to the actual magnitudes.
SVG Displacement Map
Now we translate our refraction calculations into something the browser can render using SVG displacement maps.
A displacement map is an image where each pixel's color tells the browser how far to sample from the current position.
It's up to the user to define which channel corresponds to which axis, but it is important to understand the constraint: Because each channel is 8 bits, the displacement is limited to a range of -128 to 127 pixels in each direction. (256 values possible in total). 128 is the neutral value, meaning no displacement.
SVG filters can only use images as displacement maps, so we need to convert our displacement vector field into an image format.
<svg colorInterpolationFilters="sRGB">
<filter id={id}>
<feImage
href={displacementMapDataUrl}
x={0}
y={0}
width={width}
height={height}
result="displacement_map"
/>
<feDisplacementMap
in="SourceGraphic"
in2="displacement_map"
scale={scale}
xChannelSelector="R"
yChannelSelector="G"
/>
</filter>
</svg><feDisplacementMap /> uses the red channel for the X axis and the green channel for the Y axis. The blue and alpha channels are ignored.
Scale
The Red (X) and Green (Y) channels are 8‑bit values (0–255). Interpreted without any extra scaling, they map linearly to a normalized displacement in [−1, 1], with 128 as the neutral value (no displacement):
The scale attribute of <feDisplacementMap /> multiplies this normalized amount:
Because our vectors are normalized using the maximum possible displacement (in pixels) as the unit, we can reuse that maximum directly as the filter’s scale:
<feDisplacementMap
in="SourceGraphic"
in2="displacement_map"
scale={maximumDisplacement} // max displacement (px) → real pixel shift
xChannelSelector="R"
yChannelSelector="G"
/>You can also animate scale to fade the effect in/out—no need to recompute the map (useful for artistic control even if not physically exact).
Vector to Red-Green values
To convert our displacement vector field into a displacement map, we need to convert each vector into a color value. The red channel will represent the X component of the vector, and the green channel will represent the Y component.
We currently have polar coordinates (angle and magnitude) for each vector, so we need to convert them to Cartesian coordinates (X and Y) before mapping them to the red and green channels.
const x = Math.cos(angle) * magnitude;
const y = Math.sin(angle) * magnitude;Because we normalised our vectors already, magnitude here is between 0 and 1.
From here, we just remap the values to the range of 0 to 255 for the red and green channels:
const result = {
r: 128 + x * 127, // Red = X component
g: 128 + y * 127, // Green = Y component
b: 128, // Blue ignored
a: 255, // Fully opaque
};After converting every vector in the map to color value, we get an image that can be used as a displacement map in the SVG filter.
Interactive Playground
Experiment with the liquid glass effect by adjusting parameters in real-time:
Surface
Controls
Radius Simulation
Displacement Map
Radius Displacements
Preview
Specular Highlight
The final piece is the specular highlight—those bright edges you see on real glass when light hits at certain angles.
Apple implements this as a rim light effect where highlight intensity varies based on the surface normal's angle relative to a fixed light direction.
Combining Refraction and Specular Highlight
In the final SVG filter, we combine both the displacement map for refraction and the specular highlight effect.
Both are loaded as separate <feImage /> elements, and then combined using <feBlend /> to overlay the highlight on top of the refracted image.
But this part is actually the most "creative" part of the effect, and it's just by tweaking the number of filters, and their parameters, that you can get a variety of different looks.
Using as backdrop-filter
This is where cross-browser compatibility ends. Only Chromium based browsers and Apple's Own Safari supports SVG filters as backdrop-filter:
.glass-panel {
backdrop-filter: url(#liquidGlassFilterId);
}Note: The backdrop-filter dimensions don't adjust automatically to element size—you need to ensure filter images match your element sizes.
Bringing it all Together: Real UI Components
With refraction math and displacement maps working, you can create real-world UI components. Here are some examples:
Chrome‑specific demo
Chrome allows using SVG filters as backdrop-filter, which
isn't part of the CSS spec.
Above, we used regular filter so it's viewable in
Safari/Firefox.
The next components use backdrop-filter, so they're
Chrome‑only.
Magnifying Glass
A draggable lens that refracts and magnifies the content beneath it:
Liquid Glass—Precision Lens
Drag the capsule to bend the page. This lens is a compact SVG displacement rig that refracts whatever sits beneath it.
The field comes from a rounded bezel profile; pixels are pushed along its gradient, then topped with a subtle specular bloom for depth.
Sweep across strong edges—high contrast makes the bend snap.
Searchbox
A search input with subtle glass refraction effect:
Switch
A toggle switch using the "lip" bezel profile—convex outside, concave inside—creating a unique optical effect:
Slider
A range slider with liquid glass rendering on the thumb:
Music Player
This fake music player UI tries to mimic the look of Apple Music's Liquid Glass panels, using a convex bezel and a subtle specular highlight.
It relies on the iTunes Search API to fetch album art and song details.
Conclusion
This prototype distills Apple's Liquid Glass into real‑time refraction plus a simple highlight. It's flexible but Chrome‑bound—only Chromium exposes SVG filters as backdrop-filter. That said, it's viable inside Chromium‑based runtimes like Electron.
Treat this as experimental. Dynamic shape/size changes are costly because nearly every tweak (besides animating filter props like scale) forces a full displacement map rebuild.
Thank you all for reading this article. I hope you found it interesting and informative as this is my First Comprehensive and Detailed Article on Apple's Liquid Glass and would be writing more articles on UI/UX and Web Development journey as I progress.
Related Components
Check out these ready-to-use Liquid Glass components that you can install in your projects:
- Slide to Unlock — An iOS 26-inspired liquid glass slide-to-unlock switch
- Liquid Glass Slider — A draggable slider with SVG refraction effects
- Liquid Glass Searchbox — A searchbox with focus animations and glass effects