Backdrop filters
Backdrop filter utilities apply graphic effects to the area behind an element, not to the element itself: the content underneath is blurred, brightened or recoloured where the element covers it. They are the building block for frosted glass panels, sticky headers over scrolling content and overlays that soften the page behind a dialog.
How backdrop filters work
Section titled “How backdrop filters work”- Two kinds of class. Filter classes (
backdrop-blur-md,backdrop-brightness-90,backdrop-hue-rotate-180) only set an internal custom property such as--nu-backdrop-blur. Thebackdrop-layerclass writes thebackdrop-filterproperty that combines all of them. A filter class on its own has no visible effect. - Combine freely. Because each filter is its own property, several filter classes stack on one
backdrop-layer:backdrop-layer backdrop-blur-md backdrop-brightness-90blurs and darkens. - Presets work alone.
backdrop-frosted,backdrop-glass,backdrop-dark-glass,backdrop-crystalandbackdrop-mattesetbackdrop-filterdirectly and need nobackdrop-layer.backdrop-noneremoves the filter. - Transparent element required. The effect shows only through a transparent or semi-transparent background. An element with an opaque background hides the filtered backdrop completely.
| Class | Sets | Needs backdrop-layer |
|---|---|---|
backdrop-layer |
backdrop-filter composed from the eight --nu-backdrop-* properties |
|
backdrop-blur-{key} |
--nu-backdrop-blur |
Yes |
backdrop-brightness-{key} |
--nu-backdrop-brightness |
Yes |
backdrop-contrast-{key} |
--nu-backdrop-contrast |
Yes |
backdrop-grayscale-{key} |
--nu-backdrop-grayscale |
Yes |
backdrop-hue-rotate-{key} |
--nu-backdrop-hue-rotate |
Yes |
backdrop-invert-{key} |
--nu-backdrop-invert |
Yes |
backdrop-saturate-{key} |
--nu-backdrop-saturate |
Yes |
backdrop-sepia-{key} |
--nu-backdrop-sepia |
Yes |
backdrop-frosted, backdrop-glass, backdrop-dark-glass, backdrop-crystal, backdrop-matte |
backdrop-filter |
No |
backdrop-none |
backdrop-filter: none |
No |
The backdrop layer
Section titled “The backdrop layer”backdrop-layer emits two rules. The first gives every filter property its identity value, a value that changes nothing, such as blur(0) or brightness(100%). It sits inside :where(), which has no specificity, so any filter class overrides it wherever it appears in the stylesheet. The second rule writes the combined filter:
:where(.backdrop-layer) { --nu-backdrop-blur: blur(0); --nu-backdrop-brightness: brightness(100%); --nu-backdrop-contrast: contrast(100%); --nu-backdrop-grayscale: grayscale(0); --nu-backdrop-hue-rotate: hue-rotate(0deg); --nu-backdrop-invert: invert(0); --nu-backdrop-saturate: saturate(100%); --nu-backdrop-sepia: sepia(0);}.backdrop-layer { -webkit-backdrop-filter: var(--nu-backdrop-blur) var(--nu-backdrop-brightness) var(--nu-backdrop-contrast) var(--nu-backdrop-grayscale) var(--nu-backdrop-hue-rotate) var(--nu-backdrop-invert) var(--nu-backdrop-saturate) var(--nu-backdrop-sepia); backdrop-filter: var(--nu-backdrop-blur) var(--nu-backdrop-brightness) var(--nu-backdrop-contrast) var(--nu-backdrop-grayscale) var(--nu-backdrop-hue-rotate) var(--nu-backdrop-invert) var(--nu-backdrop-saturate) var(--nu-backdrop-sepia);}Every backdrop-filter declaration in core, presets and backdrop-none included, is preceded by the same -webkit-backdrop-filter declaration.
Each filter class replaces one of these values. Filters run in the fixed order of the declaration (blur, brightness, contrast, grayscale, hue rotate, invert, saturate, sepia), whatever order the classes are written in.
In the example below, the lower half of the image is covered by three transparent panels. Only the panels with a filter change what shows through them.
<div class="relative overflow-hidden rounded-lg"> <img class="block w-full" src="/images/og-image.png" alt="NuvoUI logo with the tagline Human-readable SCSS for modern devs" /> <div class="absolute inset-x-0 bottom-0 h-50p grid cols-3"> <div class="flex center x-center p-2 text-white text-sm font-bold">No filter</div> <div class="backdrop-layer backdrop-blur-md flex center x-center p-2 text-white text-sm font-bold">backdrop-layer backdrop-blur-md</div> <div class="backdrop-blur-md flex center x-center p-2 text-white text-sm font-bold">backdrop-blur-md alone: no effect</div> </div></div>.caption-bar { @include apply(backdrop-layer, backdrop-blur(md));}Filters
Section titled “Filters”Every filter has a class for each key of its map and a mixin of the same family. The mixins accept the keys and also custom values (see Keys and custom values).
| Filter | Class | Keys and values |
|---|---|---|
| Blur | backdrop-blur-{key} |
none 0, sm 2px, md 4px, lg 8px, xl 16px, 2xl 32px |
| Brightness | backdrop-brightness-{key} |
none 100%, 75, 90, 110, 125, 150 (percent) |
| Contrast | backdrop-contrast-{key} |
none 100%, 75, 90, 110, 125, 150 (percent) |
| Grayscale | backdrop-grayscale-{key} |
none 0, 25, 50, 75, 100 (percent) |
| Hue rotate | backdrop-hue-rotate-{key} |
0, 90, 180, 270 (degrees) |
| Invert | backdrop-invert-{key} |
none 0, 25, 50, 75, 100 (percent) |
| Saturate | backdrop-saturate-{key} |
none 100%, 50, 75, 125, 150, 200 (percent) |
| Sepia | backdrop-sepia-{key} |
none 0, 25, 50, 75, 100 (percent) |
The none key of each filter (and 0 for hue rotate) is its identity value: it switches one filter off while the others on the same layer stay active. The hue rotate classes are named backdrop-hue-rotate-*, like the backdrop-hue-rotate() mixin.
<div class="relative overflow-hidden rounded-lg"> <img class="block w-full" src="/images/og-image.png" alt="NuvoUI logo with the tagline Human-readable SCSS for modern devs" /> <div class="absolute inset-0 grid cols-2"> <div class="backdrop-layer backdrop-grayscale-100 flex center x-center p-2 text-white text-sm font-bold">grayscale-100</div> <div class="backdrop-layer backdrop-hue-rotate-180 flex center x-center p-2 text-white text-sm font-bold">hue-rotate-180</div> <div class="backdrop-layer backdrop-blur-sm backdrop-brightness-150 flex center x-center p-2 text-white text-sm font-bold">blur-sm brightness-150</div> <div class="backdrop-layer backdrop-invert-100 flex center x-center p-2 text-white text-sm font-bold">invert-100</div> </div></div>.muted-overlay { @include apply(backdrop-layer, backdrop-grayscale(100), backdrop-blur(sm));}Presets
Section titled “Presets”Presets write a complete backdrop-filter value. They do not read the --nu-backdrop-* properties, so filter classes on the same element do not change them.
| Class | backdrop-filter |
|---|---|
backdrop-frosted |
blur(8px) saturate(90%) brightness(120%) |
backdrop-glass |
blur(8px) saturate(120%) contrast(90%) |
backdrop-dark-glass |
blur(8px) saturate(180%) brightness(70%) contrast(90%) |
backdrop-crystal |
blur(8px) saturate(150%) |
backdrop-matte |
blur(20px) saturate(90%) brightness(90%) |
<div class="relative overflow-hidden rounded-lg"> <img class="block w-full" src="/images/og-image.png" alt="NuvoUI logo with the tagline Human-readable SCSS for modern devs" /> <div class="absolute inset-x-0 bottom-0 h-50p grid cols-5"> <div class="backdrop-frosted flex center x-center p-1 text-white text-sm font-bold">frosted</div> <div class="backdrop-glass flex center x-center p-1 text-white text-sm font-bold">glass</div> <div class="backdrop-dark-glass flex center x-center p-1 text-white text-sm font-bold">dark-glass</div> <div class="backdrop-crystal flex center x-center p-1 text-white text-sm font-bold">crystal</div> <div class="backdrop-matte flex center x-center p-1 text-white text-sm font-bold">matte</div> </div></div>.site-header { @include apply(backdrop-frosted);}Presets come after backdrop-layer in the stylesheet, so a preset on the same element as backdrop-layer wins at the same breakpoint.
Removing the filter
Section titled “Removing the filter”backdrop-none sets backdrop-filter: none and returns every --nu-backdrop-* property to its identity value, so a composed filter added later starts from a clean state. Use it with a responsive variant to switch the effect off at a breakpoint.
<div class="relative overflow-hidden rounded-lg"> <img class="block w-full" src="/images/og-image.png" alt="NuvoUI logo with the tagline Human-readable SCSS for modern devs" /> <div class="absolute inset-x-0 bottom-0 h-50p backdrop-frosted backdrop-none@md flex center x-center p-2 text-white font-bold"> backdrop-frosted backdrop-none@md: resize the window </div></div>Responsive variants
Section titled “Responsive variants”Every class on this page, including backdrop-layer and the presets, has a responsive variant with an @{breakpoint} suffix. Variants apply from their breakpoint upwards.
<div class="relative overflow-hidden rounded-lg"> <img class="block w-full" src="/images/og-image.png" alt="NuvoUI logo with the tagline Human-readable SCSS for modern devs" /> <div class="absolute inset-x-0 bottom-0 h-50p backdrop-layer backdrop-blur-sm backdrop-blur-xl@md flex center x-center p-2 text-white font-bold"> backdrop-blur-sm backdrop-blur-xl@md </div></div>.panel { @include apply(backdrop-layer, backdrop-blur(sm), backdrop-blur(xl) md);}The identity values of backdrop-layer@md also sit in :where(), so adding backdrop-layer@md does not reset a filter that a base class such as backdrop-blur-md has set.
| Suffix | Media query |
|---|---|
@xs | @media (min-width: 480px) |
@sm | @media (min-width: 640px) |
@md | @media (min-width: 768px) |
@lg | @media (min-width: 1024px) |
@xl | @media (min-width: 1280px) |
@2xl | @media (min-width: 1536px) |
There are no state classes such as hover:backdrop-blur-md. The mixins accept state modifiers inside apply():
.card { @include apply(backdrop-layer, backdrop-blur(sm), backdrop-blur(lg) hover);}Each filter has a mixin that sets its --nu-backdrop-* property. Include backdrop-layer first: it resets every property to its identity value, so a filter mixin written before it in the same rule is overwritten.
@use "@nuvoui/core" as *;
.overlay { @include apply(backdrop-layer, backdrop-blur(lg), backdrop-saturate(150));}.overlay { --nu-backdrop-blur: blur(0); --nu-backdrop-brightness: brightness(100%); --nu-backdrop-contrast: contrast(100%); --nu-backdrop-grayscale: grayscale(0); --nu-backdrop-hue-rotate: hue-rotate(0deg); --nu-backdrop-invert: invert(0); --nu-backdrop-saturate: saturate(100%); --nu-backdrop-sepia: sepia(0); -webkit-backdrop-filter: var(--nu-backdrop-blur) var(--nu-backdrop-brightness) var(--nu-backdrop-contrast) var(--nu-backdrop-grayscale) var(--nu-backdrop-hue-rotate) var(--nu-backdrop-invert) var(--nu-backdrop-saturate) var(--nu-backdrop-sepia); backdrop-filter: var(--nu-backdrop-blur) var(--nu-backdrop-brightness) var(--nu-backdrop-contrast) var(--nu-backdrop-grayscale) var(--nu-backdrop-hue-rotate) var(--nu-backdrop-invert) var(--nu-backdrop-saturate) var(--nu-backdrop-sepia); --nu-backdrop-blur: blur(8px); --nu-backdrop-saturate: saturate(150%);}| Mixin | Output |
|---|---|
backdrop-layer |
The eight identity values and the composed backdrop-filter |
backdrop-blur($value) and the other seven filter mixins |
One --nu-backdrop-* property |
backdrop-frosted, backdrop-glass, backdrop-dark-glass, backdrop-crystal, backdrop-matte |
backdrop-filter with the preset value |
backdrop-none |
backdrop-filter: none and the eight identity values |
backdrop-filter($value) |
backdrop-filter with the value as written |
The filter mixins are backdrop-blur, backdrop-brightness, backdrop-contrast, backdrop-grayscale, backdrop-hue-rotate, backdrop-invert, backdrop-saturate and backdrop-sepia.
Keys and custom values
Section titled “Keys and custom values”A filter mixin accepts a key of its map, as an unquoted or quoted number (backdrop-brightness(90) and backdrop-brightness("90") both give brightness(90%)). Any other value must carry the unit of that filter:
| Mixin | Custom values |
|---|---|
backdrop-blur |
A length in px, rem or em |
backdrop-hue-rotate |
An angle in deg, rad, grad or turn |
| All others | A percentage |
Every filter mixin also accepts a unitless 0, calc() and var().
.sheet { @include apply(backdrop-layer, backdrop-blur(6px), backdrop-brightness(80%), backdrop-hue-rotate(45deg));}.themed { @include apply(backdrop-layer, backdrop-blur(var(--sheet-blur)));}For a filter list that the layer cannot express, such as a filter twice or a different order, use backdrop-filter(). It writes the value as given, without validation, and replaces any composed or preset filter.
.overlay { @include backdrop-filter(blur(6px) saturate(140%));}Configuration
Section titled “Configuration”The value maps ($backdrop-blur-values, $backdrop-brightness-values, $backdrop-contrast-values, $backdrop-grayscale-values, $backdrop-hue-rotate-values, $backdrop-invert-values, $backdrop-saturate-values, $backdrop-sepia-values) and $backdrop-filter-presets are configurable through @use ... with. Each map replaces the default; it is not merged.
@use "@nuvoui/core" with ( $generate-utility-classes: true, $backdrop-blur-values: ("none": 0, "sm": 3px, "md": 6px, "lg": 12px));The backdrops feature flag turns off every class on this page. The mixins stay available.
@use "@nuvoui/core" with ( $generate-utility-classes: true, $feature-flags: ("backdrops": false));generate-backdrop-filter-utilities($breakpoint: null) emits the full class set, with an @{breakpoint} suffix when a breakpoint is given. Call it at the top level, or inside the matching media query for a suffixed set; inside a rule, the classes are nested under that rule’s selector.
@media (min-width: 1800px) { @include generate-backdrop-filter-utilities(3xl);}Errors
Section titled “Errors”Filter mixins fail at compile time instead of emitting a filter that the browser would drop.
| Input | Error |
|---|---|
backdrop-blur(7) |
backdrop-blur(7): use a key (none, sm, md, lg, xl, 2xl), a value in px, rem, em, calc() or var(). |
backdrop-blur(huge) |
backdrop-blur(huge): use a key (none, sm, md, lg, xl, 2xl), a value in px, rem, em, calc() or var(). |
backdrop-brightness(80px) |
backdrop-brightness(80px): use a key (none, 75, 90, 110, 125, 150), a value in %, calc() or var(). |
backdrop-saturate(1.5) |
backdrop-saturate(1.5): use a key (none, 50, 75, 125, 150, 200), a value in %, calc() or var(). |
backdrop-hue-rotate(45) |
backdrop-hue-rotate(45): use a key (0, 90, 180, 270), a value in deg, rad, grad, turn, calc() or var(). |
// error.panel { @include backdrop-saturate(1.5);}Browser support
Section titled “Browser support”Core emits every backdrop-filter declaration twice, first as -webkit-backdrop-filter and then as the standard property, so browsers that only understand the prefixed property get the same filter. It does not wrap the classes in @supports. Browsers that support neither ignore both, and the element shows its own background over an unfiltered backdrop.
Design for the unfiltered case as well: give the element a background colour that keeps its content readable without the blur, and use @supports (backdrop-filter: blur(1px)) to make that background more transparent only where the filter works.
.site-header { background-color: token(bg-surface);
@supports (backdrop-filter: blur(1px)) { background-color: transparent; @include apply(backdrop-frosted); }}CSS variables
Section titled “CSS variables”The --nu-backdrop-* properties are internal utility properties, not tokens: token() does not accept them and they do not change with the theme.
| Variable | Set by | Identity value |
|---|---|---|
--nu-backdrop-blur |
backdrop-blur-*, backdrop-blur() |
blur(0) |
--nu-backdrop-brightness |
backdrop-brightness-*, backdrop-brightness() |
brightness(100%) |
--nu-backdrop-contrast |
backdrop-contrast-*, backdrop-contrast() |
contrast(100%) |
--nu-backdrop-grayscale |
backdrop-grayscale-*, backdrop-grayscale() |
grayscale(0) |
--nu-backdrop-hue-rotate |
backdrop-hue-rotate-*, backdrop-hue-rotate() |
hue-rotate(0deg) |
--nu-backdrop-invert |
backdrop-invert-*, backdrop-invert() |
invert(0) |
--nu-backdrop-saturate |
backdrop-saturate-*, backdrop-saturate() |
saturate(100%) |
--nu-backdrop-sepia |
backdrop-sepia-*, backdrop-sepia() |
sepia(0) |
These properties are not registered with @property, so they inherit. A backdrop-layer resets all eight on its own element, which keeps a filter set on an ancestor from leaking into a nested layer.
Class reference
Section titled “Class reference”Generated from the compiled core build. Responsive variants are not listed. The :where(.backdrop-layer) identity rule shown in The backdrop layer is not part of this table.
Layer and none (2 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-layer | -webkit-backdrop-filter: var(--nu-backdrop-blur) var(--nu-backdrop-brightness) var(--nu-backdrop-contrast) var(--nu-backdrop-grayscale) var(--nu-backdrop-hue-rotate) var(--nu-backdrop-invert) var(--nu-backdrop-saturate) var(--nu-backdrop-sepia)backdrop-filter: var(--nu-backdrop-blur) var(--nu-backdrop-brightness) var(--nu-backdrop-contrast) var(--nu-backdrop-grayscale) var(--nu-backdrop-hue-rotate) var(--nu-backdrop-invert) var(--nu-backdrop-saturate) var(--nu-backdrop-sepia) | var(--nu-backdrop-blur) var(--nu-backdrop-brightness) var(--nu-backdrop-contrast) var(--nu-backdrop-grayscale) var(--nu-backdrop-hue-rotate) var(--nu-backdrop-invert) var(--nu-backdrop-saturate) var(--nu-backdrop-sepia)var(--nu-backdrop-blur) var(--nu-backdrop-brightness) var(--nu-backdrop-contrast) var(--nu-backdrop-grayscale) var(--nu-backdrop-hue-rotate) var(--nu-backdrop-invert) var(--nu-backdrop-saturate) var(--nu-backdrop-sepia) |
.backdrop-none | -webkit-backdrop-filter: nonebackdrop-filter: none--nu-backdrop-blur: blur(0)--nu-backdrop-brightness: brightness(100%)--nu-backdrop-contrast: contrast(100%)--nu-backdrop-grayscale: grayscale(0)--nu-backdrop-hue-rotate: hue-rotate(0deg)--nu-backdrop-invert: invert(0)--nu-backdrop-saturate: saturate(100%)--nu-backdrop-sepia: sepia(0) | nonenoneblur(0)brightness(100%)contrast(100%)grayscale(0)hue-rotate(0deg)invert(0)saturate(100%)sepia(0) |
Blur (6 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-blur-none | --nu-backdrop-blur: blur(0) | blur(0) |
.backdrop-blur-sm | --nu-backdrop-blur: blur(2px) | blur(2px) |
.backdrop-blur-md | --nu-backdrop-blur: blur(4px) | blur(4px) |
.backdrop-blur-lg | --nu-backdrop-blur: blur(8px) | blur(8px) |
.backdrop-blur-xl | --nu-backdrop-blur: blur(16px) | blur(16px) |
.backdrop-blur-2xl | --nu-backdrop-blur: blur(32px) | blur(32px) |
Brightness (6 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-brightness-none | --nu-backdrop-brightness: brightness(100%) | brightness(100%) |
.backdrop-brightness-75 | --nu-backdrop-brightness: brightness(75%) | brightness(75%) |
.backdrop-brightness-90 | --nu-backdrop-brightness: brightness(90%) | brightness(90%) |
.backdrop-brightness-110 | --nu-backdrop-brightness: brightness(110%) | brightness(110%) |
.backdrop-brightness-125 | --nu-backdrop-brightness: brightness(125%) | brightness(125%) |
.backdrop-brightness-150 | --nu-backdrop-brightness: brightness(150%) | brightness(150%) |
Contrast (6 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-contrast-none | --nu-backdrop-contrast: contrast(100%) | contrast(100%) |
.backdrop-contrast-75 | --nu-backdrop-contrast: contrast(75%) | contrast(75%) |
.backdrop-contrast-90 | --nu-backdrop-contrast: contrast(90%) | contrast(90%) |
.backdrop-contrast-110 | --nu-backdrop-contrast: contrast(110%) | contrast(110%) |
.backdrop-contrast-125 | --nu-backdrop-contrast: contrast(125%) | contrast(125%) |
.backdrop-contrast-150 | --nu-backdrop-contrast: contrast(150%) | contrast(150%) |
Grayscale (5 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-grayscale-none | --nu-backdrop-grayscale: grayscale(0) | grayscale(0) |
.backdrop-grayscale-25 | --nu-backdrop-grayscale: grayscale(25%) | grayscale(25%) |
.backdrop-grayscale-50 | --nu-backdrop-grayscale: grayscale(50%) | grayscale(50%) |
.backdrop-grayscale-75 | --nu-backdrop-grayscale: grayscale(75%) | grayscale(75%) |
.backdrop-grayscale-100 | --nu-backdrop-grayscale: grayscale(100%) | grayscale(100%) |
Hue rotate (4 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-hue-rotate-0 | --nu-backdrop-hue-rotate: hue-rotate(0deg) | hue-rotate(0deg) |
.backdrop-hue-rotate-90 | --nu-backdrop-hue-rotate: hue-rotate(90deg) | hue-rotate(90deg) |
.backdrop-hue-rotate-180 | --nu-backdrop-hue-rotate: hue-rotate(180deg) | hue-rotate(180deg) |
.backdrop-hue-rotate-270 | --nu-backdrop-hue-rotate: hue-rotate(270deg) | hue-rotate(270deg) |
Invert (5 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-invert-none | --nu-backdrop-invert: invert(0) | invert(0) |
.backdrop-invert-25 | --nu-backdrop-invert: invert(25%) | invert(25%) |
.backdrop-invert-50 | --nu-backdrop-invert: invert(50%) | invert(50%) |
.backdrop-invert-75 | --nu-backdrop-invert: invert(75%) | invert(75%) |
.backdrop-invert-100 | --nu-backdrop-invert: invert(100%) | invert(100%) |
Saturate (6 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-saturate-none | --nu-backdrop-saturate: saturate(100%) | saturate(100%) |
.backdrop-saturate-50 | --nu-backdrop-saturate: saturate(50%) | saturate(50%) |
.backdrop-saturate-75 | --nu-backdrop-saturate: saturate(75%) | saturate(75%) |
.backdrop-saturate-125 | --nu-backdrop-saturate: saturate(125%) | saturate(125%) |
.backdrop-saturate-150 | --nu-backdrop-saturate: saturate(150%) | saturate(150%) |
.backdrop-saturate-200 | --nu-backdrop-saturate: saturate(200%) | saturate(200%) |
Sepia (5 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-sepia-none | --nu-backdrop-sepia: sepia(0) | sepia(0) |
.backdrop-sepia-25 | --nu-backdrop-sepia: sepia(25%) | sepia(25%) |
.backdrop-sepia-50 | --nu-backdrop-sepia: sepia(50%) | sepia(50%) |
.backdrop-sepia-75 | --nu-backdrop-sepia: sepia(75%) | sepia(75%) |
.backdrop-sepia-100 | --nu-backdrop-sepia: sepia(100%) | sepia(100%) |
Presets (5 rules)
| Selector | Declarations | Default value |
|---|---|---|
.backdrop-frosted | -webkit-backdrop-filter: blur(8px) saturate(90%) brightness(120%)backdrop-filter: blur(8px) saturate(90%) brightness(120%) | blur(8px) saturate(90%) brightness(120%)blur(8px) saturate(90%) brightness(120%) |
.backdrop-glass | -webkit-backdrop-filter: blur(8px) saturate(120%) contrast(90%)backdrop-filter: blur(8px) saturate(120%) contrast(90%) | blur(8px) saturate(120%) contrast(90%)blur(8px) saturate(120%) contrast(90%) |
.backdrop-dark-glass | -webkit-backdrop-filter: blur(8px) saturate(180%) brightness(70%) contrast(90%)backdrop-filter: blur(8px) saturate(180%) brightness(70%) contrast(90%) | blur(8px) saturate(180%) brightness(70%) contrast(90%)blur(8px) saturate(180%) brightness(70%) contrast(90%) |
.backdrop-crystal | -webkit-backdrop-filter: blur(8px) saturate(150%)backdrop-filter: blur(8px) saturate(150%) | blur(8px) saturate(150%)blur(8px) saturate(150%) |
.backdrop-matte | -webkit-backdrop-filter: blur(20px) saturate(90%) brightness(90%)backdrop-filter: blur(20px) saturate(90%) brightness(90%) | blur(20px) saturate(90%) brightness(90%)blur(20px) saturate(90%) brightness(90%) |
Accessibility and RTL
Section titled “Accessibility and RTL”- Check contrast against the busiest backdrop. Text on a blurred panel sits on whatever scrolls or shows behind it, so its contrast changes with the content. Test the lightest and darkest content that can appear behind the text, and add a semi-transparent background colour behind the text when the blur alone does not reach 4.5:1 for body text or 3:1 for large text (WCAG 1.4.3).
- More blur is more stable. A small blur keeps edges and text of the backdrop recognisable, which competes with the foreground text. Larger keys (
lgand up) or a preset give a calmer, more even surface. - Readable without the filter. Where the filter is not supported or not rendered, the panel shows its plain background. Make sure the content is still readable then (see Browser support).
- Reduced transparency. Some users ask the operating system for less transparency. Core has no mixin for the
prefers-reduced-transparencymedia query; in your own CSS, replace the glass effect with an opaque background under@media (prefers-reduced-transparency: reduce). - Performance. Backdrop filters are rendered on every frame in which the content behind them changes. Large filtered areas over scrolling or animated content can drop frames on low-end devices; keep the filtered area as small as the design allows and avoid animating the blur radius.
- RTL. Backdrop filters do not depend on text direction.