标签归档:background-size

响应式SPRITES图片实现方法探究

腾讯云正在走向全面支持响应式和Retina屏的道路上,我们广泛使用了SVG Sprites技术。在实践过程出现了“某些元素的背景图片来自于一张SVG Sprites,同时该元素也需要支持响应式”的情况,就需要解决“在元素尺寸发生变化时,来自Sprites的这张背景图片如何同步等比缩放?“的问题。

我曾经探讨过“响应式图像”的实现方法,当然这些方法都不适用背景图。我们来分解下这个问题,具体要完成哪些任务?

HTML元素在缩放时,如何保持宽高比不变?

对于这个问题,我在“使用PADDING-TOP:(PERCENTAGE)实现响应式背景图片”这篇文章中给出了解决方法,不再赘述。

See the Pen responsive image sprites 1 by wenjul (@wenjul) on CodePen.

Sprites中的背景图片如何跟随容器尺寸的变化而等比缩放?

background-size正是用来解决这个问题的。大家应该比较熟悉关键字“cover“(缩放背景图片以完全覆盖背景定位区,可能背景图片部分看不见)和”contain“(缩放背景图片以完全装入背景定位区,可能背景定位区部分空白)的效果,这两个关键字主要解决整张背景图如何适应容器,比较适用于单张图片,不适用于Sprites图。

如何计算background-size: <percentage>?

百分比值(<percentage>)是背景图相对于背景定位区(background positioning area)的百分比,可以控制在容器元素内仅显示Sprites图的部分内容。比如下图中,Sprites图是由四张头像拼成的,要想在容器内仅显示第一张头像,background-size的值应该多少呢?

demo-1

先看下100%的效果,也就是说Sprites图和容器是1:1的比例,显然不是我们要的效果。

demo-2

我们仅需要Sprites图的1/4显示在容器内,那么Sprites图与容器的比例应该是4:1,计算公式为:

background-size : ( Sprites width / image width) (Sprites height / image height)

demo-3

上面这个公式比较容易理解,但是如何在容器元素显示其他的头像呢?

当然是通过background-position来改变背景图片的初始位置。我们通常使用<length>(如px)控制背景图片相对于容器元素的偏移量,显然不适用我们这种情况,因为整张Sprites图片是可以等比缩放的,那么单张图片的左上角相对于Sprites图片的左上角的距离也是变化的,所以使用<length>是会出错的,如下例。

demo-4

如何计算background-position: <percentage>?

background-position值还可以使用 <percentage>和关键词(top, bottom, left, right, center),可以把关键词理解为<percentage>特殊形式,两者的计算方式是相同的。但是,<percentage>和<length>的计算方式是不同的:<length>的参照点是图片的左上角,<percentage>的参照点是随着取值变化的。

background-position:30px 40px; 为例,计算方法为:Sprites图的左上角相对于容器元素的左上角向右偏移30px,向下偏移40px。

demo-5

background-position:<percentage>就大不同了:如background-position:0% 0%(或top left)是将图片的左上角与容器元素的左上角对齐,background-position:100% 100%(或bottom right)是将图片的右下角与容器元素的右下角对齐,background-position:50% 50%(或center center)是将图片的中心点与容器元素的中心点对齐,background-position:33% 15%是将图片的横向33%和纵向15%的交汇点放置在容器元素的横向33%与15%的交汇点上。

demo-6

理解 <percentage>和<length>之间计算方式的差异是至关重要的。那么如果要在容器元素内显示第二张图片,怎么计算<percentage>的具体值呢?

demo-7

我们已知的信息如下:

  • 容器元素的尺寸:elW * elH
  • 单张图片的尺寸:imgW * imgH
  • Sprites图片的尺寸:spritesW * spritesH
  • 单张图片在Sprites图上的位置:imgPosX, imgPosY

我们假设:

  • 点的位置为 (x, y)
  • 容器上的(x, y)点与容器左上角的距离为 cX, cY
  • Sprites图上的(x, y)点与本张图片左上角的距离为 sX, sY

如果要把某张图片完全显示在容器元素内,我们可以推导出:

  • elW = imgW, elH = imgH
  • cX = sX, cY = sY

根据上面的信息,我就可以计算出具体的(x, y)值了,下面以 x% 为例:

  • cX = elW * x
  • sX = spritesW * x – imgPosX
  • elW * x = spritesW * x – imgPosX

解方程后就得到计算公式了:

  • x = imgPosX / (spritesW – elW) = imgPosX / (spritesW – imgW)
  • y = imgPosY / (spritesH – elH) = imgPosY / (spritesH – imgH)

把我们上面例子的信息代入方程式:

  • x = w / (4w -w) = 1/3
  • y = 0 / (h – h ) = 0

查看效果

手动计算累死人?Maxim来解救你!

Maxim是我们团队开发的可视化的构建工具,支持windows和Mac,开发时无需考虑background-sizebackground-position,发布时将文件拖入Maxim内,自动完成Sprites拼合,并补全background-sizebackground-position值,轻松实现响应式Sprites图。Maxim的更多功能也等你发现,赶快下载一个试试吧!!!

Retina显示屏下ICON优化方法

便于理解,先来了解几个名词:

  • dpi(dots per inch),每英寸的点数,用来测量任何设备的硬件分辨率。一个21”的屏幕可以拥有1680 X 1050 的分辨率,27”的屏幕也可以拥有相同的分辨率,那么大屏幕比小屏幕的dpi小。
  • dip(device independent pixels),设备独立像素,与160 dpi显示屏上的1px相等, 又称dp。
  • dppx(dots per ‘px’),每px单位上的点数。由于CSS英寸与CSS像素的固定比是1:96,那么1dppx=96dpi。
  • Device pixel ratio (DPR)是物理像素与CSS像素的比率。

方法一:media queries & background-size

查看demo

/*
** 注意:background-size的值是sprite.png的尺寸,而不是每个icon的尺寸
*/
.sprite-icon{
    background-image:url(sprite.png);
    background-size:98px 65px;       
}

/*
** 每个icon的background-positon只需写一次,即icon相对与1x图片的位置,在@2x图片中的位置也是这个
*/
.icon-1{
    background-position:0 0;
}
.icon-2{
    background-position:-33px 0;
}
.icon-3{
    background-position:-66px 0;
}
.icon-4{
    background-position:0 -33px;
}
.icon-5{
    background-position:-33px -33px;
}
.icon-6{
    background-position:-66px -33px;
}

/* 
** 2x图片要是1x图片的准确2倍
** sprite中图标之间的间隙,也应是2倍
** 每个图标无需重新写background-position
*/
@media (min-resolution:2dppx), /* Standard syntax */
(-webkit-min-device-pixel-ratio:2)  /* Safari & Android Browser */
{
    .sprite-icon{
        background-image:url(sprite@2x.png); 
    }  
}

方法二:background-image:img-set( url(a.png) 1x, url(a@2x.png) 2x )

媒体查询(media queries)已经可以解决高密度显示问题,为什么还需要image-set? 问的好。 使用image-set的两个主要好处:

  • 与媒体查询不同的是,image-set没有告诉浏览器使用哪个图片,而是提供了一些选项。我希望将来在低网速下使用高密度设备,能够告诉浏览器使用低分辨率图片。如果浏览器能够根据当前的网络状况智能地选择使用的图片,那就更好了。 媒体查询的问题是没有给浏览器任何自由裁决权,它明确的指明,如果像素密度大于1或者2,浏览器就使用特定的图片。 我知道,这只是理论上(更是“意淫“出来)的好处。如今支持“image-set”的浏览器只是简单将图片源与显示密度相匹配,并没有提供额外的功能。但我坚信,同一张图片需要不同分辨率时,让浏览器去选择合适的图片是方向。
  • CSS编码好处:将不同分辨率的图片源集中在一起。

查看demo

/* ** 注意: ** 图片要求:2x图片要是1x图片的准确2倍,sprite中图标之间的间隙也应是2倍 ** 无需写background-size,浏览器自动处理 ** */ 
.sprite-icon{ 
    background-image:url(sprite.png); 
    background-image: -webkit-image-set( url('sprite.png') 1x, url('sprite@2x.png') 2x ); 
}

/* ** 每个icon的background-positon只需写一次,即icon相对与1x图片的位置,在@2x图片中的位置也是这个 */ 
.icon-1{
     background-position:0 0; 
} 
.icon-2{ 
    background-position:-33px 0; 
} 
.icon-3{ 
    background-position:-66px 0; 
} 
.icon-4{ 
    background-position:0 -33px; 
} 
.icon-5{ 
    background-position:-33px -33px; 
} 
.icon-6{ 
    background-position:-66px -33px; 
}

方法三: media queries & background-size,适用于仅部分图标提供了2x图,且icon位置不对应,可能是由工具生成的sprite。

查看demo

.sprite-icon{
    background-image:url(more.png);
}
.icon-1{
    background-position:0 0;
}
.icon-2{
    background-position:-33px 0;
}
.icon-3{
    background-position:-66px 0;
}
.icon-4{
    background-position:0 -33px;
}
.icon-5{
    background-position:-33px -33px;
}
.icon-6{
    background-position:-66px -33px;
}
.icon-7{
    background-position:0 -66px;
}

/* 
** 每个icon的backgroud-size是2x图片的一半
** 每个icon的backgroud-position是相对与2x图片的位置除以2
*/
@media (min-resolution:2dppx), /* Standard syntax */
(-webkit-min-device-pixel-ratio:2)  /* Safari & Android Browser */
{
    .icon-1{
        background-image:url(portion@2x.png); 
        background-size:197px 65px;
        background-position:0 0;
    }
    .icon-2{
        background-image:url(portion@2x.png); 
        background-size:197px 65px;
        background-position:-33px 0;
    }
    .icon-3{
        background-image:url(portion@2x.png); 
        background-size:197px 65px;
        background-position:-66px 0;
    }
    .icon-4{
        background-image:url(portion@2x.png);
        background-size:197px 65px;
        background-position:-99px -33px;
    }
    .icon-5{
        background-image:url(portion@2x.png); 
        background-size:197px 65px;
        background-position:-132px -33px;
    }
    .icon-6{
        background-image:url(portion@2x.png);
        background-size:197px 65px;
        background-position:-165px -33px;
    }

}