w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.44k stars 657 forks source link

[css-images] Turbulence/noise image function #1273

Open AmeliaBR opened 7 years ago

AmeliaBR commented 7 years ago

From Henrik Andersson on the www-style mailing list:

As many image effect specialists can tell you, noise can be used well in various effects.

As such, I think that it would be useful if there was a way to generate noise images in css.


From me:

The web platform already has a way to generate a noise image, the <feTurbulence> filter primitive. However, using it to generate a rectangle of noise requires:

Which is a lot of messing around in markup for a stylistic effect. A CSS-only shorthand would be nice.

Turbulence doesn't make sense as a shorthand filter function, because the filter shorthands only work with a single image processing line, starting with the original and modifying it on each step. Most uses of noise would want to modify the noise and composite or blend it with the original rendering of the element.

However, a noise primitive could be very useful as an image layer in a background image stack, now that we have background-blend-mode. And even more so when/if browsers implement the filter() function for modifying an image value.

I'm imagining something like

background-image:
    filter(turbulence(stitch 0.2/3), saturate(10%)), 
    linear-gradient(lightBlue, darkRed);
background-size: 3em 3em, 100% 100%;
background-blend-mode: hard-light;

Considering that browsers already implement the feTurbulence algorithms, it probably wouldn't be too difficult to implement (although there are a few open issues on the spec that need to be resolved).

It could even be easily polyfilled using SVG data URIs (or as easy as any other CSS polyfill, anyway).

Initial proposal, to be added to CSS Images 4:


Noise images

A noise image generates a rectangular region of Perlin noise, following the algorithms described for the <feTurbulence> filter primitive. A noise image is drawn into a box with the dimensions of the concrete object size. However, the image itself has no intrinsic dimensions.

There are two noise image functions, corresponding to the two noise algorithms. The amount of noise is determined by a base-frequency (usually a decimal between 0 and 1) in the horizontal and vertical directions, and by the number of octaves (multiples of the base frequency) which are compounded (an integer, usually between 1 and 10). The noise function can be "stiched" across edges to provide a smooth appearance when the image is tiled (such as in a repeating background image). An optional seed parameter can be used to further alter the final generated noise.

<noise-image> = [<turbulence> | <fractal-noise>]
<turbulence> = turbulence( <noise-parameters> )
<fractal-noise> = fractal-noise( <noise-parameters> )

<noise-parameters> = [stitch | no-stitch]? <base-frequency> 
                         [/ <num-octaves>]? [seed  <seed>]?
<base-frequency> = <non-negative-number>{1,2}
<num-octaves> = <non-negative-integer>
<seed> = <integer> (or <number>: feTurbulence allows decimals, but truncates them)

The default values are no-stitch, <num-octaves>=1, and <seed>=0, matching the defaults for feTurbulence. A single <base-frequency> value is used for both x and y.


AmeliaBR commented 7 years ago

Here's a pen showing what the end result of my sample CSS would look like (implemented using an SVG data URI, but not a full polyfill): https://codepen.io/AmeliaBR/pen/Gmqgyg?editors=1011

background-image:
    filter(turbulence(stitch 0.2/3), saturate(10%)), 
    linear-gradient(lightBlue, darkRed);
background-size: 3em 3em, 100% 100%;
background-blend-mode: hard-light;

Screenshot of the generated background from the linked pen, with the randomized texture over the blue to red gradient

smfr commented 7 years ago

Would you want the noise image to change every time the UA renders, or be fixed for a given image?

AmeliaBR commented 7 years ago

By having the seed as a parameter (with a fixed default), it would be fixed: a given image function and image dimensions would always generate the same result. An author could use JS and CSS variables if they wanted to randomize the seed.

bradkemper commented 7 years ago

That would be cool.

I'm also still hoping we can do an svg at-rule, as described at https://github.com/jonathantneal/postcss-write-svg/blob/master/README.md, to encapsulate some of the complexity of this sort of thing into something more readable.

bradkemper commented 7 years ago

Maybe I shouldn't say "this sort of thing", but in cases where a data uri for svg needs to be considered, or in cases where it might be more readable than multiple embedding of functions.

jimmyfrasche commented 1 year ago

This would be handy, especially with #6807 and #7666. Should it be updated to use the per-element randomness from #2826?