学完这篇,你能分清图片模糊到底是「图本身不够大」还是「CSS 渲染方式不对」,并按原因用对应方法修好。
第一步:先定位模糊来源,别急着加滤镜
图片发虚通常是四类原因之一:原图分辨率低于显示尺寸、高分屏没有提供 2x/3x 图、transform 缩放产生半像素重采样、以及你自己写了 filter: blur() 忘了删。先确认是哪一类,再动手。
在 Chrome 里按 F12 打开开发者工具,点击左上角的「选择元素」箭头(快捷键 Ctrl+Shift+C),点中那张图,看 Elements 面板里 <img> 的尺寸提示:悬停时会显示「已显示尺寸」和「原始尺寸」,前者大于后者就是被放大了。
注意:不要用「给图片加 filter: blur(0)」之类的偏方去修,那只是给 GPU 加了一层不必要的合成,问题没解决。
第二步:原图不够大,就换图或限制显示尺寸
如果确认是放大导致的模糊,唯一的正解是换更大的图,或者在 CSS 里锁住显示上限,让它永远不要超过自然尺寸:
.post img {
max-width: 100%;
height: auto;
}
max-width: 100% 只会在容器变窄时缩小,不会撑大,是最省事的兜底写法。
第三步:高分屏用 srcset 提供 2x/3x 图
在 Retina 屏(DPR = 2 或 3)上,一张 300px 宽的图会被拉伸到 600 物理像素渲染,看起来就发虚。用 srcset 让浏览器自己挑:
<img src="photo.jpg"
srcset="photo.jpg 1x, photo@2x.jpg 2x, photo@3x.jpg 3x"
alt="示例图">
也可以用宽度描述符配合 sizes,适合响应式布局:
<img src="photo-480.jpg"
srcset="photo-480.jpg 480w, photo-960.jpg 960w, photo-1440.jpg 1440w"
sizes="(max-width: 600px) 100vw, 480px"
alt="示例图">
注意:srcset 里的 1x 图不要省略,否则不支持的旧浏览器没有回退源,会直接显示空白。
第四步:缩放时选对 image-rendering
image-rendering 决定浏览器缩放图片时的采样算法:
.photo-thumb {
width: 120px;
height: 120px;
object-fit: cover;
image-rendering: auto; /* 照片缩小,交给浏览器高质量插值 */
}
.pixel-icon {
image-rendering: pixelated; /* 像素画、8bit 图标放大时保持硬边 */
}
注意:pixelated 用在人像照片上会变成马赛克,反过来在像素风图标上用 auto 会糊成一团,两者别搞混。
第五步:transform 造成的模糊,改成整数像素布局
transform: translate(-50%, -50%) 居中时,元素宽度是奇数就会落在 .5 像素上,浏览器重采样后就发虚;scale(1.2) 同样会引入非整数缩放。优先改用 flex 居中:
.center {
display: flex;
align-items: center;
justify-content: center;
}
如果必须保留 transform 动画,可以在动画元素上加 will-change: transform;,让浏览器提前提升为合成层,减少中途重绘造成的模糊。
第六步:背景图模糊的处理
background-size: cover 本身不会降低清晰度,但背景图没有 2x 版本一样会糊。用媒体查询按 DPR 换图:
.hero {
background: url(photo@1x.jpg) center / cover no-repeat;
}
@media (min-resolution: 2dppx) {
.hero {
background-image: url(photo@2x.jpg);
}
}
另外别写 background-size: 100% 100%,那会强行拉伸变形,看起来更模糊。
第七步:确实是想要「毛玻璃」,别让子元素一起糊
filter: blur() 会作用在整个元素上,包括里面的文字。想只模糊背景,用伪元素单独承载:
.card {
position: relative;
overflow: hidden;
}
.card::before {
content: "";
position: absolute;
inset: 0;
background: url(bg.jpg) center / cover;
filter: blur(12px);
transform: scale(1.08); /* 遮掉模糊产生的半透明边缘 */
z-index: -1;
}
注意:伪元素没设 z-index: -1 会盖住正文;边缘发白是模糊扩散到元素外的正常现象,用 scale 稍微放大即可盖住。
小结
- 先用开发者工具对比「原始尺寸」和「显示尺寸」,确认是放大还是渲染问题。
- 图太小就换图,并加
max-width: 100% 兜底。
- 高分屏用
srcset + sizes 提供 2x/3x 图,1x 图不能省。
- 照片缩放用
image-rendering: auto,像素画才用 pixelated。
- 居中优先用 flex,避免
translate(-50%, -50%) 产生半像素。
- 背景图用
@media (min-resolution: 2dppx) 换高清图,别写 100% 100%。
- 毛玻璃效果用伪元素承载
filter: blur(),父级加 overflow: hidden 防止溢出。