问题描述
使用 uni-app 开发时,部分 SVG 图标在 iOS 端显示模糊,但在 Android 端显示正常。
由于 SVG 属于矢量图片,最初怀疑是 iOS 端先将 SVG 栅格化,再按照组件尺寸进行缩放。因此尝试将 SVG 的宽高放大为原来的 4 倍,但显示效果没有改善。
排查过程
检查 SVG 文件后发现,出现模糊的图标都包含阴影滤镜,例如:
xml
<filter>
<feGaussianBlur />
<feDropShadow />
</filter>
随后移除 SVG 内部的阴影效果,在 uni-app 的 iOS 真机环境中重新测试,图标恢复清晰。
由此确认,问题主要与 SVG 内部的阴影滤镜有关。
产生原因
在 uni-app 中,SVG 最终会交由不同平台的渲染引擎处理。iOS 端基于 WebKit 的渲染机制,对包含滤镜的 SVG 可能采用离屏位图渲染:
- 先将 SVG 图形绘制到临时位图;
- 使用高斯模糊生成阴影;
- 将处理后的位图缩放到组件尺寸;
- 再与页面内容进行合成。
SVG 的主体图形虽然是矢量的,但加入阴影后,整个图层可能转为位图处理。阴影边缘包含大量半透明像素,经过缩放和插值后,容易出现边缘发虚、灰边或整体模糊。
因此,单纯放大 SVG 的宽高并不能解决问题,因为最终仍可能发生位图缩放。
解决方案
方案一:移除 SVG 内部阴影
删除 SVG 中的滤镜定义及引用:
xml
<filter>...</filter>
以及:
xml
filter="url(#shadow)"
这是最稳定的方案,适合对清晰度要求较高的图标。
方案二:将阴影迁移到外层元素
在 uni-app 页面中,可以给图片或图标外层元素添加 CSS 阴影:
vue
<view class="icon-wrapper">
<image
class="icon"
src="/static/icons/refresh.svg"
mode="aspectFit"
/>
</view>
scss
.icon-wrapper {
filter: drop-shadow(12rpx 16rpx 18rpx rgba(0, 0, 0, 0.22));
}
.icon {
width: 180rpx;
height: 180rpx;
}
对于规则矩形元素,也可以使用:
scss
.card {
box-shadow: 12rpx 16rpx 18rpx rgba(0, 0, 0, 0.22);
}
方案三:使用无滤镜版本的图标资源
如果项目中同一图标存在多个版本,建议优先使用不包含阴影和模糊滤镜的 SVG 文件,再通过 uni-app 外层样式实现视觉效果。
uni-app 中的验证建议
排查此类问题时,应优先使用 iOS 真机或 iOS 模拟器验证,重点检查:
- SVG 是否包含
filter、feGaussianBlur、feDropShadow; - 是否设置了透明度、渐变或复杂遮罩;
<image>的显示尺寸是否存在非整数缩放;- 移除 SVG 阴影后是否恢复清晰;
- 阴影迁移到外层 CSS 后,Android 和 iOS 是否表现一致。
总结
在 uni-app 项目中,SVG 图标在 iOS 端模糊,通常与 SVG 内部阴影滤镜触发位图渲染有关,而不是单纯的图片尺寸问题。移除 SVG 内部阴影,或将阴影迁移到外层 CSS,是更稳定的处理方式。