话不多说,直接弄!
效果
实现
本次我们使用神奇的SVG来实现,还是挺简单的,这里就为大家拆分一下步骤,一步步来实现。
1. 基础画布创建
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
</svg>
这就是最基础的一张svg画布了,我们直接设置宽高100%,让其撑满。
2. 滤镜制作
有了画布还不够,我们还需要一个盛放(展示)内容的容器以及对容器中内容的相关滤镜。
2.1 基础结构
单纯写滤镜我们无法直观看到效果,这里我们就使用rect矩形来使用滤镜。其基础结构如下:
<filter id="filter">
// 后续滤镜内容
</filter>
<rect width="100%" height="100%" filter="url(#filter)" />
我们给滤镜写了一个id,在对应的矩形中我们应用一下即可。
2.2 噪声纹理
我们使用 feTurbulence 来生成噪声。feTurbulence 会使用柏林噪声函数生成一个程序纹理,常用于云彩、烟雾、大理石、金属等纹理的基础噪声。和PS中添加云彩效果类似。
先给出代码,然后解析:
<feTurbulence baseFrequency=".002 .02" numOctaves="9" result="n" />
-
baseFrequency=".002 .02":这是一个噪声频率,数值越小,纹理越宽大柔和;数值越大,纹理越密集细碎。 这里 x 方向 0.002、y 方向 0.02,相当于竖直方向的变化更密集,容易做出类似“竖向拉丝”的感觉。 -
numOctaves="9": 表示叠加 9 个不同频率的噪声八度层,频率一层比一层高(两倍),细节越来越多。层数越多,图案越复杂、越精细,但性能开销也更大。通常 3~6 已经足够。 -
result="n":给当前输出起个名字叫n(noise 缩写),方便后面滤镜引用。
2.3 添加光源
<feDiffuseLighting surfaceScale="9" lighting-color="#ba8c63">
<feDistantLight elevation="60" azimuth="-90" />
</feDiffuseLighting>
feDiffuseLighting 滤镜会把输入图像的 alpha 当作高度信息,模拟漫反射光照,生成一张光照后的颜色图,有明显的高光和阴影。 内部的 feDistantLight 则是指定光源方向。
这里对其中几个参数左下说明:
-
surfaceScale="9":控制“高度起伏”的强度,可以理解为凹凸有多深。数值越大,明暗对比越强,越有金属 / 皮革的起伏感。 -
lighting-color="#ba8c63":光的颜色,因为我们要木材纹理,因此这里是棕金色,更贴近木头的颜色。 -
elevation="60":光照的高度角(0° 在地平线,90° 直射),60° 是比较高的斜上方光源。 -
azimuth="-90":光源方位角,单位是度。这里从左侧照向右侧,从而产生从左到右的光感。
2.4 添加扭曲
到上一步其实材质效果已经出来了,但是还缺乏类似年轮的扭曲效果,因此为了更真那么一点点,就增加一个扭曲滤镜来优化一下。
<feDisplacementMap in2="n" scale="50" />
feDisplacementMap 会使用第二个输入(in2 )的颜色通道作为位移向量,把第一个输入(in )的像素往各个方向挪动,从而产生类似水波、玻璃扭曲、抖动等效果。这个滤镜非常常见,以后也会分享一些相关的效果。
in2="n":位移图使用第一步feTurbulence生成的噪声n。scale="50":位移强度,数值越大,扭曲越严重。
到这里就是我们上面效果图的样式。
拓展点
1. 噪声的可选属性
在我们上述的噪声纹理中,其实还可以增加一些属性来进行更多的控制。例如 type 和 seed。
type:控制噪声的类型,更躁动还是更柔和,有两个值turbulence:更激烈的噪声,明暗对比明显。fractalNoise:更柔和连续,适合云雾、柔和纹理。
seed:随机种子,相同 seed 会生成同样的噪声,不同 seed 会产生不同纹理。
例如,我们可以将噪声改为更柔和的样式
<feTurbulence type="fractalNoise" baseFrequency=".002 .02" numOctaves="9" seed="2" result="n" />
2. 光源的输入与输出
案例中 feDiffuseLighting 没有显式写 in="n",浏览器会把它的输入默认为前一个滤镜输出(即上面的 feTurbulence)。
输出结果默认会用一个自动生成的名字(如果不指定 result),这里没有继续显式引用,就直接被下一个滤镜作为链式输入(SVG 会按顺序串联)。
完整写法为
<feDiffuseLighting in="n" result="light" surfaceScale="9" lighting-color="#ba8c63">
<feDistantLight elevation="60" azimuth="-90" />
</feDiffuseLighting>
3. 扭曲滤镜的第一输入与通道控制
在我们给的例子中,最后的扭曲滤镜 feDisplacementMap 只有 in2 而未写 in ,默认把上一步 feDiffuseLighting 的输出作为主图像输入。
在完整写法之中,也会有指定通道选择,例如 xChannelSelector="R" / yChannelSelector="G":指定使用位移图的红色通道控制 x 方向位移,绿色通道控制 y 方向位移。
我们省略了 xChannelSelector 和 yChannelSelector ,会使用默认通道,但大部分简单场景效果仍然可用的。
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="filter">
<feTurbulence baseFrequency=".002 .02" numOctaves="9" result="n" />
<feDiffuseLighting surfaceScale="9" lighting-color="#ba8c63">
<feDistantLight elevation="60" azimuth="-90" />
</feDiffuseLighting>
<feDisplacementMap in2="n" scale="50" />
</filter>
<rect width="100%" height="100%" filter="url(#filter)" />
</svg>
参考资料:
你可以在这里找到大鹅所有CSS知识分享哦
![]()
![]()
![]()
![]()
![]()
【冷门知识】鹅のCSS大合集!长期追更~ 收藏 ≈ 学会



