最直接的浮雕实现方式是用 filter: url(#emboss) 调用 SVG 中定义的 滤镜,需正确设置 3×3 卷积核、order="3"、preserveAlpha="true" 和 targetX/targetY="1",兼容现代浏览器但不支持 IE/旧 Edge。

用 filter: url(#emboss) 调用 SVG 滤镜是最直接的浮雕实现方式
HTML5 本身没有内置“浮雕”滤镜函数,filter: emboss() 并不存在。真正可用的是通过内联 SVG 定义 滤镜,再用 CSS 的 filter: url(#id) 引用。这种方式兼容 Chrome、Firefox、Safari(桌面端),但不支持 IE 和旧版 Edge。
关键点在于卷积核(convolution kernel)的设计:浮雕本质是方向性边缘增强,常用 3×3 核如 [1, 0, 0, 0, -1, 0, 0, 0, 0] 或更典型的 [2, 0, 0, 0, -1, 0, 0, 0, -1],需配合 order="3"、preserveAlpha="true" 避免透明通道被错误处理。
-
targetX和targetY建议设为1,确保中心像素对齐 - 若图片有透明背景,必须加
preserveAlpha="true",否则阴影区域会发灰或失真 - 滤镜 ID(如
#emboss)必须与 CSS 中url(#emboss)完全一致,大小写敏感
Canvas 手动实现浮雕:用 getImageData + 灰度差分
当需要动态控制强度、适配不支持 SVG 滤镜的环境(如某些 WebView),Canvas 是更稳妥的选择。核心逻辑是:先转灰度,再对每个像素计算右下邻域的亮度差,映射为偏移后的 RGB 值。
注意不是简单套用高斯模糊再减原图——浮雕是定向梯度近似,推荐用右下方向差分:gray(x+1,y+1) - gray(x,y),结果归一化到 0–255 后同时加到 R/G/B 通道,模拟光照错觉。
立即学习“前端免费学习笔记(深入)”;
- 必须使用
ctx.getImageData(0, 0, width, height)获取原始像素,canvas.toDataURL()无法反向操作 - 循环时需跳过最右列和最下行(避免越界),或用
Math.min边界保护 - 差分结果常为负值,建议用
128 + Math.round(diff * strength)基线偏移,strength通常取 1.0–2.5 - 性能敏感场景下,避免在每帧重复执行;可预生成
Uint8ClampedArray缓存结果
filter: drop-shadow() 不能替代浮雕,但可快速模拟浅浮雕感
有人尝试用多重 drop-shadow()(如 drop-shadow(1px 1px 0 #000) drop-shadow(-1px -1px 0 #fff))伪造浮雕,这仅适用于纯色图标或文字,对照片类图片完全失效:它不感知边缘,只叠加固定偏移的色块,容易出现毛边、光晕或颜色污染。
真实浮雕依赖像素级亮度梯度,而 drop-shadow 是层叠式绘制,无空间卷积能力。只有当图像内容极简(如 SVG path、单色 icon)、且只要视觉“近似”时,才可临时应急。
- 慎用于 PNG 透明图:阴影会透出背景色,破坏明暗逻辑
- 多层 shadow 在 Safari 上可能触发渲染 bug,表现为阴影位移异常
- 无法响应鼠标悬停动态调整浮雕角度——SVG 滤镜或 Canvas 方案才能做到
移动端 Safari 的 feConvolveMatrix 兼容性陷阱
iOS 15.4+ 支持 ,但存在两个隐蔽问题:一是 kernelUnitLength 若设为非 1 值(如 "2"),会导致滤镜完全不生效;二是当图片通过 object-fit: cover 缩放后,滤镜仍按原始尺寸计算,造成浮雕偏移或拉伸。
- 强制设
kernelUnitLength="1",不要省略 - 对响应式图片,改用 Canvas 方案,或监听
resize重绘 SVG 滤镜区域 - 测试时务必用真机 —— iOS 模拟器常误报滤镜可用
- 若必须用 SVG 滤镜,建议 fallback 到
filter: contrast(1.2) brightness(0.95)作为视觉降级
实际应用中,浮雕效果的“真实感”不取决于算法多复杂,而在于灰度转换是否准确、差分方向是否匹配预期光源(默认假设光从左上方来,就该用右下差分),以及 alpha 通道是否被干净隔离。多数失败案例,都卡在没关掉 preserveAlpha 或忘了处理图片缩放带来的坐标偏移。










