最近工作中制作移动端活动页面的时候,由于图片较多,因此频繁使用到CSS Sprites,此时会遇到了一个常见问题——在不同分辨率下,background-position定位的图片的边缘有可能被裁剪,显示不全。
对比几种CSS Sprites的适配方法
目前为止,我知道并尝试过的适配方法有如下几种:
- rem
- 百分比
- zoom
- transform scale
通过制作demo,我们对一张CSS Sprites进行展示,通过上述几种方法,在iphone6下就出现了图片展示不全的问题(红框中的图片的边缘被裁剪),如下图:
由于rem、百分比单位最终都会被浏览器解析成px进行渲染,分辨率不同生成的px值一般会存在小数点,而浏览器对小数点的解析也不一样。IE7-和safari会对小数点取整,而IE8+、chrome、firefox等浏览器则会四舍五入。因此浏览器对rem、百分比单位转换成px时,很容易因为1px的差而导致CSS Sprites定位不准而造成边缘被裁剪的现象。
在以往的项目中,用得最多的是百分比,其精度相对于rem较好点,出现图标被裁剪的情况较少。但是在这个项目中,利用百分比依旧不如人意。
百分比定位参考文章:http://zhangruojun.com/backgroud-positionde-bai-fen-bi-zhi/?utm_source=tuicool&utm_medium=referral
之后尝试了使用zoom的方法,直接对图标进行缩放,效果却和rem差不多。
rem和zoom的解决方案
针对上面的rem和zoom方法的解决方案是,制作CSS Sprite时图标之间相隔远一点,css中图标尺寸设置大一点,background-position的值相对原值小一点。
比如,正常设置如下:
// rem
.icon{
width: 0.2rem;
height: 0.2rem;
background-position: -1rem -0.8rem;
}
// zoom
.icon{
width: 20px;
height: 20px;
background-position: -100px -80px;
}
采用解决方案后的设置如下:
// rem
.icon{
width: 0.24rem;
height: 0.24rem;
background-position: -0.98rem -0.78rem;
}
// zoom
.icon{
width: 24px;
height: 24px;
background-position: -98px -78px;
}
效果图如下,基本上解决了图标被裁剪的问题:
不过上述解决方案,我认为在代码上总是要想着时刻加减原值,而且后期维护的时候如果忽略了该解决方法,很容易又会出现上述问题。此外,在页面布局上,图标在页面中的位置容易出现1px的偏差,在元素布局的时候也需要注意这个误差。
transform scale方法
由zoom缩放自然联想到了transform里的scale缩放方法。
关于zoom和transform scale的区别可以查看这两篇文章:
http://www.zhangxinxu.com/wordpress/2015/11/zoom-transform-scale-diff/
http://www.cnblogs.com/Hchun/p/5291400.html
transform scale方法代码:
.icon{
width: 20px;
height: 20px;
background-position: -100px -80px;
}
//设计稿宽度为640px,所有值均和设计稿取值一致
@media only screen and (max-width: 320px){
.icon{-webkit-transform:scale(0.5);transform:scale(0.5);}
}
单纯地用transform scale方法,确实可以较完美地解决边框被裁剪的问题,但是其在页面中的位置却不对了。探究发现有两个原因:
- transform scale默认情况下是相对于元素中心进行缩放的。
- transform scale只会对元素本身进行缩放,在页面渲染的时候,会先渲染元素原始的大小,再进行缩放。缩放的时候不会再引起页面的重绘,因此元素原始尺寸有多大,就会占据页面多大的空间,和缩放无关。
那有没有解决方案,可以保留transform scale完美呈现图标的优点,又能够实现页面精准布局的方法呢?
transform scale & :before方法
如果给元素再包裹一层容器,让父容器大小和元素一致,再让元素脱离文档流,始终相对于父容器定位呢?理论上是可以实现的,但是这样会多增加一层标签。因此,自然想到了伪元素:before和:after,让伪元素展示图标。
具体代码如下:
.icon{
width: 0.2rem;
height: 0.2rem;
position: relative;
}
.icon:before{
width: 20px;
height: 20px;
background-position: -100px -80px;
position: absolute;
left: 0;
top: 0;
-webkit-transform-origin: 0 0; //让元素相对于左上角进行缩放
transform-origin: 0 0;
}
@media only screen and (max-width: 320px){
.icon:before{-webkit-transform:scale(0.5);transform:scale(0.5);}
}
这样基本上就能保证图标完整且位置准确。
不过这个方法最大的不足,是增加了css里面的代码量。
关于rem、zoom、transform scale几种方法实现移动端的CSS Sprites,其优缺点都是显而易见的,在项目中可以根据具体情况来权衡采用哪种方法。