1概述

feSpecularLighting 用于模拟镜面反射光照。

他的核心属性如下:

  • in:输入图像
  • surfaceScale:峰值高度,默认值为 1,取值范围为 0 到 100。值越大,阴影和高光越强烈,起伏感越强
  • lighting-color:光源颜色,默认值为 white
  • specularExponent:镜面反射系数,控制高光的聚集程度(光斑大小),值越小,光斑越扩散,值越大,光斑越锐利、越小,例如抛光金属或者玻璃
  • specularConstant:镜面常数,控制高光的强度/亮度,值越大,反光越刺眼

2案例:果冻按钮

这是最基础的用法。我们将一个扁平的圆形,通过添加高光,瞬间变成具有 Q 弹质感的果冻按钮。

预览
index.tsx
1
export default function App() {
2
return (
3
<div className="w-full h-full flex flex-col items-center justify-center rounded-xl p-8 relative overflow-hidden">
4
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
5
<defs>
6
<filter id="demo1-specular-lighting">
7
{/* 1. 模糊 Alpha,制造圆润的斜坡 */}
8
<feGaussianBlur in="SourceAlpha" stdDeviation="5" result="blur" />
9
10
{/* 2. 生成高光层 */}
11
{/* specularExponent="25": 适中的光斑,看起来像软塑料或凝胶 */}
12
{/* lighting-color: 白色高光 */}
13
<feSpecularLighting
14
in="blur"
15
surfaceScale={5}
16
specularConstant={1}
17
specularExponent={25}
18
lightingColor="white"
19
result="specularOut"
20
>
21
<fePointLight x={50} y={50} z={60} />
22
</feSpecularLighting>
23
24
{/* 3. 关键步骤:合成 */}
25
{/* 将高光层 (specularOut) 叠加在原始图形 (SourceGraphic) 上 */}
26
{/* arithmetic k2="1" k3="1" 相当于简单的相加 (Add) */}
27
<feComposite
28
in="SourceGraphic"
29
in2="specularOut"
30
operator="arithmetic"
31
k1={0}
32
k2={1}
33
k3={1}
34
k4={0}
35
/>
36
</filter>
37
</defs>
38
39
{/* 原始图形:一个粉色的圆 */}
40
<circle cx={100} cy={100} r={60} fill="#ff4081" filter="url(#demo1-specular-lighting)" />
41
</svg>
42
</div>
43
);
44
}
45

3案例:金属质感

这个案例,我们使用 feSpecularLighting 来模拟一个金属质感。

金属感的秘诀在于反差。feDiffuseLighting 提供了灰暗的基调,而 feSpecularLighting (exponent=80) 提供了那一道像刀锋一样锐利的白光。

预览
index.tsx
1
export default function App() {
2
return (
3
<div className="w-full h-full flex flex-col items-center justify-center rounded-xl p-8 relative overflow-hidden">
4
<svg width="400" height="150" viewBox="0 0 400 150" xmlns="http://www.w3.org/2000/svg">
5
<defs>
6
<filter id="demo2-specular-lighting">
7
{/* 1. 模糊源图像 Alpha */}
8
<feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur" />
9
10
{/* 2. 制造暗部/体积感 (Diffuse) */}
11
{/* lightingColor="#666" 是个技巧,用它来压暗边缘,或者用深灰色 */}
12
<feDiffuseLighting
13
in="blur"
14
surfaceScale={4}
15
lightingColor="#666"
16
result="diffuseOut"
17
>
18
<feDistantLight azimuth={45} elevation={60} />
19
</feDiffuseLighting>
20
21
{/* 3. 制造锐利高光 (Specular) */}
22
{/* specularExponent="80": 非常高,模拟抛光金属的锐利反光 */}
23
<feSpecularLighting
24
in="blur"
25
surfaceScale={6}
26
specularConstant={1.5}
27
specularExponent={80}
28
lightingColor="#fff"
29
result="specularOut"
30
>
31
<feDistantLight azimuth={45} elevation={60} />
32
</feSpecularLighting>
33
34
{/* 4. 复杂的合成链 */}
35
{/* 先把 Diffuse 叠到底色上 */}
36
<feComposite
37
in="diffuseOut"
38
in2="SourceGraphic"
39
operator="arithmetic"
40
k1={1}
41
k2={0}
42
k3={0}
43
k4={0}
44
result="shaded"
45
/>
46
47
{/* 再把 Specular 加到结果上 */}
48
<feComposite
49
in="specularOut"
50
in2="shaded"
51
operator="arithmetic"
52
k2={1}
53
k3={1}
54
result="metallic"
55
/>
56
57
{/* 最后裁切掉文字外部 */}
58
<feComposite
59
in="metallic"
60
in2="SourceAlpha"
61
operator="in"
62
/>
63
</filter>
64
</defs>
65
66
<text
67
x="50%"
68
y="60%"
69
textAnchor="middle"
70
fontFamily="Impact"
71
fontSize="80"
72
fill="#aaa"
73
filter="url(#demo2-specular-lighting)"
74
>
75
METAL
76
</text>
77
</svg>
78
</div>
79
);
80
}
81

4案例:动态扫描光

这个案例,我们使用 feSpecularLighting 来模拟一个动态扫描光。

SVG 滤镜最酷的地方在于它的属性是可以动画化的。我们可以让 <fePointLight> 的坐标移动,模拟黑夜中探照灯扫过物体的效果。这非常适合做 Loading 动画或 Logo 展示。

预览
index.tsx
1
export default function App() {
2
return (
3
<div className="w-full h-full flex flex-col items-center bg-gray-900 justify-center rounded-xl p-8 relative overflow-hidden">
4
<svg width="300" height="150" viewBox="0 0 300 150" xmlns="http://www.w3.org/2000/svg">
5
<defs>
6
<filter id="moving-light" x="-50%" y="-50%" width="200%" height="200%">
7
{/* 1. 准备高度图 */}
8
<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur" />
9
10
{/* 2. 动态光照 */}
11
{/* specularExponent=35: 聚光效果明显 */}
12
<feSpecularLighting
13
in="blur"
14
surfaceScale="5"
15
specularConstant="2"
16
specularExponent="35"
17
lightingColor="#ff0055"
18
result="light"
19
>
20
{/* 点光源 */}
21
<fePointLight x="-50" y="75" z="30">
22
{/* 动画:让光从左扫到右 */}
23
<animate attributeName="x" from="-50" to="350" dur="3s" repeatCount="indefinite" />
24
</fePointLight>
25
</feSpecularLighting>
26
27
{/* 3. 合成 */}
28
{/* 我们把原始图形设为暗色,只在有光划过时变亮 */}
29
{/* 使用 arithmetic 将光照叠加在原图上 */}
30
<feComposite
31
in="light"
32
in2="SourceGraphic"
33
operator="arithmetic"
34
k1="0"
35
k2="0.2"
36
k3="1"
37
k4="0"
38
/>
39
</filter>
40
</defs>
41
42
{/* 文字本身是深灰色的,只有光照扫过才会亮起洋红色 */}
43
<text
44
x="50%"
45
y="50%"
46
dy=".3em"
47
textAnchor="middle"
48
fontFamily="Verdana"
49
fontWeight="900"
50
fontSize="60"
51
fill="#333"
52
filter="url(#moving-light)"
53
>
54
usehook
55
</text>
56
</svg>
57
</div>
58
);
59
}
60

5案例:水滴高光

这个案例,我们使用 feSpecularLighting 来模拟一个水滴高光。

  • 水滴本身几乎是透明的 (fill-opacity="0.1")。
  • 我们看到的“水滴感”完全是由 <feSpecularLighting> 生成的那个白色亮斑,以及 <feDropShadow> 生成的阴影构成的。
  • 大脑会自动填补信息:有高光、有阴影、且透视到底下的背景 = 这是一个透明的水珠。
预览
index.tsx
1
export default function App() {
2
return (
3
<div className="w-full h-full flex flex-col items-center bg-gray-800 justify-center rounded-xl p-8 relative overflow-hidden">
4
<svg width="300" height="200" viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg">
5
<defs>
6
<filter id="water-drops">
7
{/* 1. 模糊源,制造水滴的弧度 */}
8
<feGaussianBlur in="SourceAlpha" stdDeviation="6" result="blur" />
9
10
{/* 2. 生成高光 */}
11
{/* 高 surfaceScale (15) 模拟水滴的高突起 */}
12
{/* exponent=40 模拟湿润的表面 */}
13
<feSpecularLighting
14
in="blur"
15
surfaceScale={15}
16
specularConstant={2.5}
17
specularExponent={40}
18
lightingColor="#fff"
19
result="specular"
20
>
21
<fePointLight x={50} y={50} z={100} />
22
</feSpecularLighting>
23
24
{/* 3. 合成:只显示高光 + 原始的一点点透明度 */}
25
{/* 这里的关键是我们几乎丢弃了 SourceGraphic 的颜色,主要保留高光 */}
26
<feComposite in="specular" in2="SourceGraphic" operator="in" result="glint" />
27
28
{/* 4. 给水滴加一点阴影让它更立体 (可选) */}
29
<feDropShadow dx={2} dy={4} stdDeviation={3} floodOpacity={0.3} />
30
</filter>
31
</defs>
32
33
<rect width="100%" height="100%" fill="url(#bg)" />
34
35
{/* 水滴组 */}
36
{/* 颜色 fillOpacity 设为 0.1,因为水是透明的 */}
37
<g filter="url(#water-drops)" fill="white" fillOpacity={0.1}>
38
<circle cx={100} cy={80} r={30} />
39
<circle cx={180} cy={120} r={40} />
40
<path
41
d="M50,150 Q80,120 110,150 T170,150"
42
stroke="white"
43
strokeWidth={20}
44
strokeLinecap="round"
45
fill="none"
46
/>
47
</g>
48
</svg>
49
</div>
50
);
51
}
52
专栏首页
到顶
专栏目录