A glass pane that blurs and tints whatever is behind it.
Fluted Glass
Reeded glass over whatever is behind it: the box's backdrop blurred and lightly brightened, cut into vertical flutes (or flutes at an angle), each with a light edge and a shade, as a pane of fluted glass bends what is behind it into strips. Put it in a positioned box over a picture, a video or a gradient, and give it the flute's width and how far it blurs. Without backdrop-filter the flutes are drawn over the content as they are, unblurred. Decoration, hidden from a screen reader; it never takes a click. Zero JavaScript.
Live demo
Live, from the library itself: scroll, hover, navigate away and back. The demo is never gated.
Adjust · props are custom properties, set inline, so you edit the running instance
Measured
JavaScript of its own
0 B
CSS 4.6 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Chrome 76 · Firefox 103 · Safari 18; needs backdrop-filter. Elsewhere: without backdrop-filter the flutes are drawn unblurred.
Install
One command adds the integration, the base tokens and every component. Then import what you use.
npx astro add moonarcpnpm astro add moonarcbunx astro add moonarc---
import FlutedGlass from '@moonarc/core/FlutedGlass';
---
<figure style="position: relative">
<img src="/studio.webp" alt="The studio at dusk" width="1600" height="1000" />
<FlutedGlass width="28px" blur="8px" angle={8} />
</figure>Copy it into your project instead (shadcn registry)
Owns the file, no dependency. The registry item also installs the base tokens.
npx shadcn@latest add https://moonarc.dev/r/fluted-glass.jsonThe CLI needs a components.json and the @/* alias, which Setup has. The file lands in src/components/moonarc/.
Source
The whole component. Self-contained styles in a cascade layer so your classes always win; it imports nothing.
---
/**
* FlutedGlass — reeded glass over whatever is behind it: the box's backdrop blurred and lightly brightened, cut into
* vertical flutes (or flutes at an angle), each with a light edge and a shade, as a pane of fluted glass bends what is
* behind it into strips. Put it in a positioned box over a picture, a video or a gradient; give it the flute's width and
* how much it blurs. Without backdrop-filter the flutes are drawn over the content as they are, unblurred.
* Decoration, hidden from a screen reader; it never takes a click. Zero JavaScript.
*/
import type { HTMLAttributes } from 'astro/types';
interface Props extends HTMLAttributes<'div'> {
/** The flutes' width, a CSS length. */
width?: string;
/** How far the backdrop blurs, a CSS length. */
blur?: string;
/** The flutes' angle, in degrees: 0 for upright. */
angle?: number;
/** How strong the flutes' light and shade are, 0 to 1. */
strength?: number;
}
const { width = '22px', blur = '6px', angle = 0, strength = 0.5, class: className, style, ...rest } = Astro.props;
const vars = [`--ma-flute-width:${width}`, `--ma-flute-blur:${blur}`, `--ma-flute-angle:${angle}deg`, `--ma-flute-strength:${strength}`, typeof style === 'string' ? style : ''].filter(Boolean).join(';');
---
<div class:list={['ma-flute', className]} aria-hidden="true" style={vars} {...rest}></div>
<style is:global>
@layer components {
:where(.ma-flute) {
--ma-flute-width: 22px;
--ma-flute-angle: 0deg;
--ma-flute-strength: 0.5;
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
-webkit-backdrop-filter: blur(var(--ma-flute-blur, 6px)) brightness(1.04) saturate(1.1);
backdrop-filter: blur(var(--ma-flute-blur, 6px)) brightness(1.04) saturate(1.1);
/* each flute: a light edge, the clear middle, a shade before the next */
background: repeating-linear-gradient(
calc(90deg + var(--ma-flute-angle, 0deg)),
rgb(255 255 255 / calc(0.32 * var(--ma-flute-strength))) 0,
rgb(255 255 255 / calc(0.06 * var(--ma-flute-strength))) calc(var(--ma-flute-width) * 0.18),
transparent calc(var(--ma-flute-width) * 0.45),
rgb(0 0 0 / calc(0.1 * var(--ma-flute-strength))) calc(var(--ma-flute-width) * 0.82),
rgb(0 0 0 / calc(0.22 * var(--ma-flute-strength))) var(--ma-flute-width)
);
}
/* prefers-reduced-motion: nothing here moves */
}
</style>Props
| Prop | Type | Default | Description |
|---|---|---|---|
width | string | '22px' | The flutes' width. |
blur | string | '6px' | How far the backdrop blurs. |
angle | number | 0 | The flutes' angle in degrees; 0 is upright. |
strength | number | 0.5 | How strong the light edges and the shades are, 0 to 1. |
Reduced motion
Nothing in it moves.
With ClientRouter
No script: it works on any page however it was reached.
Why it is built this way
- One element: backdrop-filter blurs what is behind it, and one repeating gradient draws each flute's light edge, clear middle and shade.
- The strength scales every stop of the gradient at once, so a flute keeps its shape at any strength.
Replaces: Fluted Glass (Cult UI) · Fluted glass shader (shaderscn). See the migration table.
Related
Noise
BackgroundsFilm grain over a gradient or image, blended and flickering at 12 fps.
Progressive Blur
BackgroundsAn edge that blurs what scrolls under it, more the closer it gets: a few bands, each with a backdrop blur twice the last and a mask that keeps it to its own slice, so the blur ramps instead of stepping.
Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown