你可以给CSS渐变添加噪点吗?

66

能否在CSS中向渐变添加噪点?

这是我用于径向渐变的代码:

body {
    color: #575757;
    font: 14px/21px Arial, Helvetica, sans-serif;
    background-color: #2f3b4b;
    background: -moz-radial-gradient(center 45deg, circle closest-corner, #2f3b4b 0%, #3e4f63 100%);
    background: -webkit-gradient(radial, center center, 10, center center, 900, from(#2f3b4b), to(#3e4f63));
}

我需要在这个上面添加什么来制造噪音,给它增加纹理感?


1
为什么你没有添加普通的径向渐变? - doğukan
9个回答

115

这绝对是最轻松和最好的实现方式。它纯粹使用 CSS,非常简单易行,无需额外的文件 - 没有任何麻烦。当然,这不是最佳的实现方式,但它非常可靠(在测试非常老旧的浏览器时从未失败),加载速度非常快。

几个月前发现它,并从那以后一直在使用,只需将此代码复制并粘贴到您的 CSS 中即可。

background-image: url(data:image/png;base64,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);

然后添加你的背景颜色

background-color:#0094d0;

演示: JSFiddle

来源: https://coderwall.com/p/m-uwvg


代码中的 url() 部分到底发生了什么?有没有办法自定义粒度和其他参数? - tobias47n9e
1
@tobias47n9e URL 部分中的数据只是一个小图像。您可以将其更改为任何图像 URI 数据(谷歌“将图像转换为 URI”)。请注意,您需要的是 URI 数据而不是 URL! - tim.baker
@tim.baker 太棒了。谢谢! - tobias47n9e
由于CSS渐变技术上是background-image属性(与覆盖的data-uri相同),因此无法与渐变一起使用。 - corysimmons
3
@corysimmons 这是不正确的。要与渐变一起使用,只需在相同的 background-image 属性后面添加逗号和渐变即可。 - Orbit
显示剩余2条评论

40

使用SVG滤镜和CSS渐变创建纹理(噪声)

想要在渐变中加入噪声?你真的很幸运!

柏林噪声是一种梯度噪声。SVG标准规定了一种称为<feTurbulence>的滤镜基元,它实现了柏林函数。它允许合成人造纹理,例如云彩或大理石——这就是你想要的噪声。

第一步:定义一个SVG图形

创建一个名为noise.svg的小型SVG文件。

<svg
  xmlns='http://www.w3.org/2000/svg'
  xmlns:xlink='http://www.w3.org/1999/xlink'
  width='300' height='300'>

    <filter id='n' x='0' y='0'>
            <feTurbulence
              type='fractalNoise'
              baseFrequency='0.75'
              stitchTiles='stitch'/>
    </filter>

    <rect width='300' height='300' fill='#fff'/>
    <rect width='300' height='300' filter="url(#n)" opacity='0.80'/>
</svg>

这个图形定义了两个矩形。第一个填充了实色,而第二个应用了噪声滤波器并设置为半透明。第二个矩形覆盖在第一个上方以提供噪声效果。

SVG选项

  1. 首先可以更改图形的尺寸。但是CSS的background-repeat属性可用于填充元素,因此300×300应足够。

  2. 滤波器的type属性可以是fractalNoiseturbulence,指定滤波函数。两者都提供不同的视觉效果,但在我看来,噪声滤波器略微更加细腻。

  3. 滤波器的baseFrequency属性可以从0.5至0.9范围内变化,分别提供粗糙到细腻的纹理。在我看来,这个范围对于任一滤波器都是视觉上最佳的。

  4. 第一个矩形的fill可以更改以提供不同的基础颜色。然而,后来我们基本上将这个颜色与半透明的CSS渐变组合起来,后者也定义了一个或多个颜色。因此,白色是这里的一个好起点。

  5. 第二个矩形的opacity可以从0.2至0.9范围内变化,以设置滤波器强度,其中更高的数字增加了强度。

在这一点上,您可以调整上述选项,将这个噪声图形设置为CSS背景图像,然后结束了。但是如果像OP那样想要渐变,就请继续看第2步。

第2步:应用CSS渐变

使用background-image属性,您可以将SVG噪声图形设置为任何元素的背景,并叠加渐变。在这个例子中,我将把噪声图形应用于整个body,再叠加一个线性渐变

body {
    /* white to black linear noise gradient spanning from top to bottom */
    background:
      linear-gradient(rgba(255,255,255,.5), rgba(0,0,0,.5)),
      url('noise.svg');
}
< p > linear-gradient()函数创建一个伪图像,叠加在noise.svg上方。结果是一个透明的渐变效果,并显示出我们的噪点效果。

CSS 选项

  1. 首先,最明显的是可以更改定义的渐变色。但是,如果您想要均匀的颜色而不是渐变颜色,请使两个端点颜色相等。好处是您可以在站点或项目中使用具有或没有渐变的同一噪声图形。

  2. 可以使用*-gradient()函数创建多个图像并叠加到噪声图像上,并且可以在单个渐变函数中指定多个角度和颜色参数以提供各种酷炫的视觉效果。

  3. 渐变参数(即rgba()和hsla())的不透明度可以增加,以加强定义的颜色并减少噪声水平。同样,0.2-0.9是理想范围。

结论

这是一个高度可定制并且非常轻量级(~400字节)的解决方案,允许您简单地定义任何颜色或渐变的噪声。虽然这里有几个旋钮可以调节,但这只是开始。还有其他SVG过滤原语,例如<feGaussianBlur><feColorMatrix>,可提供其他结果。


3
关于我如何应用这种技术来匹配给定的渐变,可以参考我对这个问题的回答:https://dev59.com/5obca4cB1Zd3GeqPZ8Oj#49111298。 - Clint Pachl
4
你能提供一个演示链接吗? - hitautodestruct
你也可以通过CSS直接将SVG滤镜应用于元素,例如 body {filter: url(#n)} - Shikkediel
@ClintPachl提供了一个非常好的解决方案!感谢您。比使用画布更高效。对于任何想要查看动画版本的人,我在stackblitz中创建了一个示例https://stackblitz.com/edit/react-ts-xc2kyo - stwilz

27

目前在CSS中没有一种方法可以给背景添加“噪点”。

另一种解决方案是在图形编辑器中创建一个透明的噪点png文件,然后将该图形作为<div>的背景应用。然后需要将该<div>放置在整个<body>的区域上,这样就可以呈现出具有噪点的渐变外观。


9
可以使用多个背景图片,其中最上面的是您的噪声PNG。 支持渐变的浏览器通常也支持这些功能。 - DanMan
5
我认为叠加噪点的效果不如真实噪点好看。如果噪点叠加能使用“乘法”模式混合,效果会更好,但是CSS并不支持该功能。然而,使用带有噪点的渐变大图片也不是完美的替代方案,因为带有噪点的图像不易压缩。 - Jakob Egger
1
我们能用过滤器来实现这个吗? - Costa Michailidis
1
仅供2020年参考,因为这是最佳答案,请查看下面的其他答案。 - tim.baker

21

为了追求新颖,这里提供一些使用纯 CSS 噪声的方法而不使用数据 URI:

#box {
  width: 250px;
  aspect-ratio: 1;
  position: relative;
  background: 
    repeating-radial-gradient(closest-corner at 1% 21%, rgba(255,0,255,.5), rgba(0,255,255,.5), #000 1.7%), 
    repeating-radial-gradient(closest-corner at 51% 51%, #fff, #fff, rgba(0,255,0,1) 10%);
  background-size: 55px 10px;
}

#box::before {
  position: absolute;
  z-index: 1;
  inset: 0;
  background: 
    repeating-radial-gradient(closest-corner at 21% 21%, #fff, rgba(0,0,255,.5), rgb(3,0,255) 20%), 
    repeating-radial-gradient(closest-corner at 61% 21%, #fff, rgba(0,255,0,.5), rgb(3,0,255) 20%), 
    repeating-radial-gradient(closest-corner at 91% 51%, #fff, rgba(255,255,1,.5), rgb(055,255,255) 20%);
  background-size: 15px 13px, 12px 22px, 12px 22px;
  background-blend-mode: exclusion, normal;
  mix-blend-mode: exclusion;
  content: ''
}
<div id="box"></div>

关于这是如何创建的,以下是一些更多信息:http://jollo.org/LNT/public/css-noise.html

1
这是如何工作的?只是一堆梯度相互加减吗? - Mark Gardner

14

现在是2023年,所以我的答案是:最好的选择是使用轻量级内联SVG过滤器和一个CSS声明...其中包括背景渐变。没有外部文件,不需要对任何内容进行base64编码。此外,它能很好地保留非粗糙的渐变,因为它不会影响其对比度或亮度。

SVG过滤器如下所示:

<svg width='0' height='0'>
  <filter id='grainy' x='0' y='0' width='100%' height='100%'>
    <feTurbulence type='fractalNoise' baseFrequency='.537'/>
    <feColorMatrix type='saturate' values='0'/>
    <feBlend in='SourceGraphic' mode='multiply'/>
  </filter>
</svg>

CSS代码如下:

background: filter(radial-gradient(circle, red, tan), url(#grainy))

有什么陷阱吗?

嗯,目前(2023年初),它实际上在任何地方都不起作用,尽管它应该很快开始在Safari中运行。 Safari是唯一实现filter()函数的浏览器,它允许我们仅在background-image图层上应用filter而不影响元素的文本内容或后代。 现在,即使在Safari中,它仅适用于url()图像,但它很快也会适用于CSS渐变

我们仍然可以跨浏览器执行此操作:

background: radial-gradient(circle, mediumturquoise, darkslateblue);
filter: url(#grainy)

现场演示

然而,正如上面提到的,这个filter会影响它所设置的整个元素,包括后代和文本内容。

为了避免这种情况,我们需要将backgroundfilter声明放在一个伪元素上,绝对定位在其父元素内容的后面,覆盖其整个父元素区域 - 现场演示

这很容易实现并且跨浏览器兼容,但是最好支持filter()函数,不要仅仅为此使用一个伪元素,并且减少当前解决方法所需的CSS代码量至约15%。

因此,这里是其他浏览器中与此有关的错误链接:


还有一件事:如果你不是非常需要颗粒感,而只是想要视觉上的改进,你可以将渐变存储在一个--grad自定义属性中,并使用以下代码:

div {
    --grad: radial-gradient(circle, mediumturquoise, darkslateblue);
    background: var(--grad);
    
    @supports (background: filter(conic-gradient(red, tan), blur(1px))) {
        background: filter(var(--grad), url(#grainy))
    }
}

对于任何感兴趣的人,解释一下SVG过滤器:

  • 这个svg只是用来包含filter,它不会真正用于显示任何内容,因此我们将其尺寸设置为零(最好也在CSS中使用position: absolute将其移出流程);当它是内联的时候,它不需要其他属性(如果你想将它移到外部文件中,你需要添加xmlns='http://www.w3.org/2000/svg'

  • filter显然需要一个id来引用,但默认情况下,该过滤器效果也会在应用它的元素之外向各个方向溢出10%(对于feTurbulence有关),所以我们希望将其限制在元素的区域内,沿着两个轴从0%100%(或者,如果您不想设置所有这些属性,我猜您可以在CSS中设置clip-path: inset(0);请注意,overflow: hidden无法解决这个问题,因为它只隐藏了元素内容溢出padding-box之外的部分,而没有影响实际元素上产生的图形效果,例如filter产生的效果)

  • 第一个过滤原语创建了一个噪声层;我真的不明白这是如何工作的 - 有this article很多人推荐,但一旦从1D到2D就失去了我;我注意到的是,最好将默认type值(turbulence)切换为fractalNoise,并且baseFrequency值越小,噪声的颗粒度越细(此外,不要使用整数 - 使用7.01,而不是7

  • 第二个过滤原语完全使其输入变灰(相当于grayscale(1)saturate(0)的效果);由于我们没有明确指定输入,它默认使用前一个过滤原语的结果 - 噪声层;为此,它从feColorMatrix的默认type(即matrix)切换到saturate,并将values设置为0(如果您对HSL model/bicone有良好的心理形象,您会知道饱和度为0%意味着我们总是有一个灰色;它是多么明亮或多么暗,这取决于亮度,即“HSL”中的“L”)

  • 第三个也是最后一个过滤原语将去饱和的噪声与应用了该过滤器的元素混合;feBlend需要两个输入之一设置为“SourceGraphic”(请注意那些大写字母!),而另一个则默认使用前一个过滤原语的结果;最后,我们使用的modemultiply(这将逐像素乘以两个图层的% RGB值

这就是过滤器所需的全部内容。里面没有你不需要的任何东西。
很多时候,SVG生成器会输出许多不必要的属性,但这是手写的,我只包括了跨浏览器工作所需的内容。

9
虽然这并不算是真正的噪音,但可以采用纯CSS3方法,使用多个重复线性背景选择器,通常在图案生成器中使用。以下是一些示例: 通过正确组合背景、角度、颜色停止和透明度,应该可以实现类似噪声的效果 :) 无论如何,希望这能为您指明正确的方向...

8
目前尚无基于CSS的噪声纹理方法。然而,如果您想使用编程方法(而非基于图像的方法),则可以尝试使用HTML5画布。此处有一个使用JavaScript生成噪声的教程 -> 在HTML5 Canvas中创建噪声
但是,使用Canvas方法会导致访问者的体验变得缓慢,因为A)JavaScript是一种解释性语言,B)使用JS编写图形速度较慢。
所以,除非你试图通过使用HTML5来表明某些观点,否则建议您使用图像。这样做将更快(对于您的制作和用户加载),而且您将更好地控制外观。

在某些情况下(尤其是在移动设备上,HTTP请求更加昂贵的情况下),它甚至比实际加载速度更快! - Misha Reyzlin
1
或者你可以对图像进行base-64编码。不一定需要HTTP请求。 - derrylwc
1
我有一个经过测量的用例,其中一个带有噪声纹理的图像,大小为80x80,重达10kb,在进行base64编码后,将在CSS中添加约14kb的文本 - 这是不可接受的。在JS中,这只需要大约20行代码(http://snipplr.com/view/44066/generate-image-noise-with-canvas/),它的工作速度足够快(比通过缓慢的网络加载这14kb的文本更快)。 - Misha Reyzlin
绝对是使用JS的好理由。虽然10kb似乎有点太大了!40x40像素应该为可重复噪声纹理提供足够的熵,并且不到2kb。这完全取决于您的特定情况。 - derrylwc
你可以使用CSS来完成这个任务 :/ - tim.baker

6

在Clint Pachl的回答基础上,我使用了CSS的mix-blend-mode来获得更加颗粒感的效果,并选择性地提升了渐变中的颜色。

示例代码请参见https://jsfiddle.net/jimmmy/2ytzh30w/

更新: 我在CSS-Tricks上写了一篇关于此的文章: Grainy Gradients

Noise using css


看起来很棒,谢谢你。 - a3k

2

即使可能(即使可能,也需要大量的代码技巧来实现),也无法仅使用CSS生成噪声纹理。目前没有任何新的CSS3属性可以直接提供这种效果。一个更快的解决方案是使用图形编辑器(如Photoshop)来实现。


那你建议在Photoshop中创建一个纹理,然后在x和y方向上重复使用吗? - austin
1
@austin: 是的。你可以将噪点单独创建为重复的透明PNG,并将其作为background-image放置,或者在图像中包含径向渐变,使其不重复,虽然这样更兼容,但你必须保持它具有精确的大小。 - BoltClock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接