<br />

Web features: [box-shadow](https://webstatus.dev/features/box-shadow) [filter](https://webstatus.dev/features/filter) [mix-blend-mode](https://webstatus.dev/features/mix-blend-mode) [background-blend-mode](https://webstatus.dev/features/background-blend-mode) [isolation](https://webstatus.dev/features/isolation) [Gradients](https://webstatus.dev/features/gradients) [Gradient interpolation](https://webstatus.dev/features/gradient-interpolation) [Conic gradients](https://webstatus.dev/features/conic-gradients) [color-mix()](https://webstatus.dev/features/color-mix) [Oklab and OkLCh](https://webstatus.dev/features/oklab) [@supports](https://webstatus.dev/features/supports) [Custom properties](https://webstatus.dev/features/custom-properties) [aspect-ratio](https://webstatus.dev/features/aspect-ratio)

> [!NOTE]
> **Note:** These guides are authored for AI coding agents (apologies for the robotic tone!). To have your coding agent adopt these patterns automatically, check out [Modern Web Guidance](https://github.com/GoogleChrome/modern-web-guidance).

### Depth and texture

- Layer multiple shadows for realistic soft depth effects.
- Use `filter: drop-shadow()` instead of `box-shadow` for non-rectangular shapes or transparent PNGs.
- Use `mix-blend-mode` and `background-blend-mode` for lighting overlays (limit scope with `isolation: isolate`)

    .hero {
      background-image: url('texture.png'), linear-gradient(to bottom, #fff, #eee);
      background-blend-mode: soft-light;
    }

### Gradients and `color-mix()`

Use `in oklch` or `in oklab` to explicitly specify the interpolation color space for gradients or `color-mix()`.

- `in oklch` preserves chroma better, but can more easily get out of device gamut, especially for bigger differences between colors
- `in oklab` stays in gamut more easily (assuming in-gamut endpoints) but can create washed out desaturated colors in the middle, especially when interpolating between opposite hues.
- *DON'T* use `in srgb` unless you have a specific reason to do so (e.g. you are building a color picker that needs to interpolate in srgb).

#### Fallback

Some pre-2024 browsers do not support gradient color interpolation space.
To support these browsers, use the token only when its usage is safe by defining a variable:

    :root {
      --in-oklab: ;
      --in-oklch: ;
    }

    @supports (linear-gradient(in oklab, white, black)) {
      :root {
        --in-oklab: in oklab;
        --in-oklch: in oklch;
      }
    }

Then use like:

    .card {
      background: linear-gradient(to bottom var(--in-oklab), var(--accent-color), var(--darker));
    }

- **Important:** If you use this technique, make sure there is always a non-empty gradient preamble without it, otherwise it will be a syntax error in older browsers.
- You do NOT need this for `color-mix()`. If a browser supports `color-mix()`, it also supports its `in <color-space>` argument.

### Patterns

Many patterns can be created via CSS gradients + hard stops, and these can be more flexible and performant than SVGs or external images as they can have access to CSS variables and lengths from the surrounding context.
You don't need to repeat the position twice --- just use `0` or `0%` and gradient fixup will auto-adjust it.

Examples below.

Vertical stripes of `1em` width each:

    background: linear-gradient(to right, var(--color-1) 50%, var(--color-2) 0) 0 / 2em;

Diagonal stripes of `1em` width each:

    background: repeating-linear-gradient(-45deg, var(--color-1) 0 1em, var(--color-2) 0 2em);

Checkerboard pattern with `1em` squares:

    background: repeating-conic-gradient(var(--color-1) 0 25%, var(--color-2) 0 50%) 0 / 2em 2em;

Polka dot with `.5em` radius dots spaced `2em` apart (horizontally/vertically --- multiply by `sqrt(2)` for diagonal distance):

    --distance: 2em;
    --radius: .5em;
    --polka: radial-gradient(circle, var(--color-1) var(--radius), transparent calc(var(--radius) + 1px));
    background: var(--polka) 0 0, var(--polka) var(--distance) var(--distance) var(--color-2);
    background-size: calc(var(--distance) * 2) calc(var(--distance) * 2);

Simple pie chart:

    .pie {
      --p: 80%;
      width: 60px;
      aspect-ratio: 1;
      border-radius: 50%;
      background: conic-gradient(var(--color-1) var(--p), transparent 0%) var(--color-2);
    }

**Important:** When using gradients to render charts, ensure there is a textual fallback for screen readers. MANDATORY: You MUST provide a semantic data table as an accessible alternative, as detailed in [Accessibility Coding Guidelines](https://developer.chrome.com/docs/modern-web-guidance/guides/accessibility/accessibility) under the alternate text and media guidelines.
Source: [visual-effects guide on GitHub](https://github.com/GoogleChrome/modern-web-guidance-src/blob/main/guides/visual-design/visual-effects/guide.md)