Bug 250303 - The filter() function doesn't work with CSS gradients
Summary: The filter() function doesn't work with CSS gradients
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Tim Nguyen (:ntim)
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2023-01-08 10:30 PST by ana.tudor.lhnh
Modified: 2023-01-08 23:10 PST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description ana.tudor.lhnh 2023-01-08 10:30:58 PST
The following works:

```
background: filter(url(image.jpg), saturate(0))
```

But using a CSS gradient doesn't:

```
background: filter(linear-gradient(red, tan), saturate(0))
```

Live test: https://codepen.io/thebabydino/pen/RwxowwV

Per spec, the `filter()` function should accept a CSS gradient. It's defined as:

```
filter() = filter( [ <image> | <string> ], <filter-value-list> )
```

And `<image>` [includes CSS gradients](https://www.w3.org/TR/css-images-3/#image-values).

This could simplify things every time we need to add some kind of filter effect to a gradient - for example noise. We can apply an SVG `filter` on the element with the gradient we want to make grainy ([live demo](https://codepen.io/thebabydino/pen/abjpEbz/66e0409358289250d9d742124994e0de)), but applying a filter on an element also affects its text content, so in order to avoid that, we need to use up a pseudo-element, which we absolutely position underneath the element's text content and move the gradient `background` and the `filter` there. Which is totally doable and cross-browser, but it would be easier to only apply the filter on the gradient background.

Right now I have to do this ([live demo](https://codepen.io/thebabydino/pen/VwBPygQ/792799a12a8db65f739295179eca82bf)):

```
div { /* just the relevant CSS */
  position: relative
}

div::before {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(circle, red, tan);
  filter: url(#grainy);
  content: '';
}
```

But it could be just this:

```
div { /* just the relevant CSS */
  background: filter(radial-gradient(circle, red, tan), url(#grainy))
}
```
Comment 1 Tim Nguyen (:ntim) 2023-01-08 20:30:57 PST
If I comment out these 2 lines, it seems to work: https://searchfox.org/wubkat/rev/c9fdb2c5fbdab38f8db4b0fe8a8f34f6801f2035/Source/WebCore/rendering/style/StyleGradientImage.cpp#191-192

Seems like a bug with StyleGradientImage::image().
Comment 2 Tim Nguyen (:ntim) 2023-01-08 21:24:22 PST
https://searchfox.org/wubkat/rev/c9fdb2c5fbdab38f8db4b0fe8a8f34f6801f2035/Source/WebCore/rendering/style/StyleCanvasImage.cpp#79 is also hit when using `filter()` with `-webkit-canvas()`
Comment 3 Tim Nguyen (:ntim) 2023-01-08 21:40:45 PST
I have a pretty straightforward fix for this.
Comment 4 Radar WebKit Bug Importer 2023-01-08 22:56:26 PST
<rdar://problem/104018718>
Comment 5 Tim Nguyen (:ntim) 2023-01-08 23:09:42 PST
Pull request: https://github.com/WebKit/WebKit/pull/8387
Comment 6 Tim Nguyen (:ntim) 2023-01-08 23:10:18 PST
Submitted web-platform-tests pull request: https://github.com/web-platform-tests/wpt/pull/37800