如何解决移动端CSS Sprite(background-position)导致的图片模糊问题?
这个问题核心是高DPI屏幕(比如Retina屏)的设备像素比(DPR)适配在搞鬼。普通<img>标签浏览器会自动帮你处理高分辨率图的缩放,但CSS背景图(Sprite)就得咱们手动干预了。我给你拆解一下解决思路和具体做法:
问题根源
比如在2x的Retina屏上,1个CSS像素对应2个物理设备像素。你要显示的是50px CSS像素的图标,实际需要100px物理像素的图才能清晰。如果直接用50px的Sprite图,浏览器会把它拉伸到100px物理像素,就会模糊;但如果做了100px的Sprite图,直接设width:100px又会让图标在视觉上变大一倍,超出预期。
正确的解决步骤
1. 制作高分辨率Sprite图
按照你目标CSS尺寸 × 目标最大DPR来做图标。比如你要50px CSS像素的图标,考虑到主流的2x和3x屏,就做100px(2x)或150px(3x)的图标,把它们拼成对应的Sprite图(比如sprites@2x.png、sprites@3x.png)。
2. 用background-size缩放Sprite图
这是关键!把高分辨率的Sprite图通过background-size缩小到和CSS目标尺寸匹配的比例。比如2x的Sprite图,原图宽度是200px(两个100px的图标),那background-size就设为100px 50px(原图尺寸除以2),这样整个Sprite会被缩放到CSS像素的比例,对应到50px的图标大小。
3. 调整background-position定位
因为Sprite图放大了DPR倍,所以定位的偏移值也要除以DPR。比如2x图里第二个图标在原图的偏移是-100px 0,那CSS里就设为-50px 0,刚好对应CSS像素的偏移。
具体代码示例
假设我们要做50px×50px的图标,用2x Sprite:
/* 第一个图标 */ .item { width: 50px; /* 保持目标CSS尺寸不变 */ height: 50px; background: url(/sprites@2x.png); background-size: 100px 50px; /* 2x原图是200x100,除以2得到这个值 */ background-position: 0 0; /* 原图偏移0,除以2还是0 */ } /* 第二个图标 */ .item-second { width: 50px; height: 50px; background: url(/sprites@2x.png); background-size: 100px 50px; background-position: -50px 0; /* 原图偏移-100px,除以2得到-50px */ }
进阶优化:适配多DPR屏幕
用image-set可以让浏览器自动根据屏幕DPR加载对应的Sprite图,不用写多套媒体查询:
.item { width: 50px; height: 50px; background-image: image-set( url(/sprites.png) 1x, url(/sprites@2x.png) 2x, url(/sprites@3x.png) 3x ); background-size: 100px 50px; /* 对应1x图的尺寸,高DPR图会自动按比例缩放 */ background-position: 0 0; }
偷懒技巧:用预处理器自动计算
如果用Sass/Less这类预处理器,可以定义变量自动计算尺寸和定位,避免手动算错:
$dpr: 2; $sprite-original-width: 200px; $sprite-original-height: 100px; $icon-css-size: 50px; .item { width: $icon-css-size; height: $icon-css-size; background: url(/sprites@#{$dpr}x.png); background-size: $sprite-original-width/$dpr $sprite-original-height/$dpr; background-position: -($icon-css-size) 0; }
这样一来,既保证了高DPI屏幕下图标清晰,又能维持50px的CSS显示尺寸,不会出现超出预期的情况。
内容的提问来源于stack exchange,提问作者Hopeless

