本文介绍一些关于响应式图像的适配应用策略,回退原理,SVG的换色技巧,雪碧图的百分比定位计算公式等相关的一些小知识点,目的在于帮助一部分同学快速的理清图像应用思路,以及一些web图像的应用技巧。
特点:应用简单,上手容易,性能表现良好
难点:lazyload实现
根据不同设备,不同分辨率,不同像素比使用的响应式图像,常用的有两种场景:
1.1 固定尺寸图像
基于设备像素比选择,很多网站logo就是固定宽度图像的一个例子,不管viewport的宽度如何,始终保持相同的宽度。
在dom里图像与在css里的图像写法如下面的例子
<img srcset="test.jpg 1.5x, test2.jpg 2x" src="test.jpg" 768.jpg 768w, 1200.jpg 1200w, 1920.jpg 1920w" sizes=" (max-width: 360px) 100vw, (max-width: 768px) 90vw, (max-width: 1980px) 80vw, 768px" src="360.jpg" src="/uploads/allimg/170502/1409454491-0.png" width="393" height="293" />在iphone4(320)下,图像宽度和我们设置的100vw一致,但是为什么浏览器选择了768的图像而没有选择360的?因为4的dpr是2呀^_^,浏览器很智能的选择了质量最合适的768.
再看一下6p(414),很听话的按照我们的设置,显示了90vw。因为他的dpr更高,浏览器聪明的选择了1200质量的图像。
这里我们可以欺骗一下浏览器:
360.jpg 1200w, 1200.jpg 9999w我们把360的图像,骗浏览器说这是1200的,然后把原本1200的扔天上去
浏览器果然上当了,他把360的图当成1200的来用了。这里可能有些疑问,图像的宽度为什么不是90vw了哪?因为浏览器被骗了但是自己却不知道,他依然按照1200的图像,去适配dpr。414*90%*(360/1200)约等于111.7。这种方式很智能,浏览器去根据你的sizes,从w列表里选择最适合的图像来调用显示。正因为他太智能了,在实际操作中可控性较差,有些我们想精确控制的图像显示,有时候并不能如意。而且在做lazyload的时候要处理的东西也比较复杂。
这个时候可以考虑另外一种方式。
1.2.2.picture元素,可精确把控
picture元素就像是图像和其源的容器。浏览器仍然需要img元素,用来表明需要加载图片,如果没有img,那么什么都不会渲染。source为浏览器提供了要显示图像的供选版本。
适用场景为:在一个精确特定的转效点(breakpoint)需要显示一个特定的图像时。使用picture元素选择图像,不会有歧义,理解起来也更直观。
<picture> <source media="(min-width: 960px)" srcset=960.jpg"> <source media="(min-width: 768px)" srcset="768.jpg"> <img src="360.jpg" target="_blank">http://snghr.tencent.com 里面使用较多也不需要去特意做回退处理,当浏览器不支持的时候就直接读取img标签。对于懒加载的回退,我选择判断IE 7-8直接url给他。
2. 特殊格式的图像应用与回退
特点:体积优化效果显著
难点:兼容性掌控上面picture元素还可以提供 基于图片格式选择。
有一些图像格式在较小的文件大小情况下保证了较好的图片质量。听起来还不错,但残酷的事实是没有一个新格式被所有浏览器支持。谷歌的WebP表现不错,但只有Chrome和Opera原声支持。JPEG-XR,最初被称为高清照片,是微软发布的一个专有图像格式,仅Internet Explorer支持
<picture> <source type="image/vnd.ms-photo" src="test.jxr"> <source type="image/jp2" src="test.jp2"> <source type="image/webp" src="test.webp"> <img src="test.png" src="/uploads/allimg/170502/14094523b-3.png" width="292" height="66" />服务端根据浏览器的请求头,返回不同的图像格式,对于X5内核还可以支持sharpP。
3. SVG应用
难点:变色方案,响应式定位计算
上面这个source的type属性还支持另一种我们更常用的图像格式,SVG。
说起SVG,这是个出现频率比webp更高的图像格式了,他有着比iconfont更多的优点,所以现在web上正在大量的应用。
优点:
1. SVG提供的功能集涵盖了嵌套转换、裁剪路径、Alpha通道、滤镜效果等能力,它还具备了传统图片没有的矢量功能,可适配任何高清屏。
2. 可读性好,有利于SEO与无障碍
与iconfont对比
1. 渲染方式不同
关于渲染方式,之前欧文同学的文章已经讲述的很清楚,这里不多做叙述(https://isux.tencent.com/svg-icon-part-one.html),无论黑白渲染,灰度渲染,次像素渲染,还是DirectWrite 或 GDI 渲染,既然iconfont他是一个字体,就难逃出现锯齿的命运,特别是在一倍屏幕下的渲染。
2. icon font只能支持单色
icon font做为字体无法支持多色图形,这就对设计造成了许多限制,因此这也成为了icon font的一个瓶颈。
3. icon font可读性不好
icon font主要在页面用Unicode符号调用对应的图标,这种方式不管是浏览器,搜索引擎和对无障碍方面的能力都没有SVG好
在对比完之前,可能有同学就会问,SVG和iconfont对比有个致命的缺点,就是换色.
比如hover换色,iconfont只要写个颜色就好了,SVG是不是需要做两个颜色的图?这也是SVG图像应用我们解决的一个难点之一
SVG换色,最初我试过三个方案
一是mask-image属性,他的优点是简单粗暴,直接用css来mask这个svg图形来进行换色,缺点很明显就是兼容性了,除去兼容性,还是很好用的。
demo:
background: #ff6600; -webkit-mask:center no-repeat; -webkit-mask-image: url(qq-logo.svg);二是通过SVG滤镜来实现,优点是效果更好,缺点除了兼容性,还需要额外的脚本配合。关于滤镜换色的详细说明在我上一篇文章里有详细介绍以及demo:http://www.uisdc.com/svg-filter-in-browser
三是我们最终选择的底层无感知换色的方案,把修改颜色的脚本集成到了我们的工作流里,我们在写css的时候,遇到svg需要换色的地方,只需要
background-image: url(test.svg?fill=#ffffff)加一句换色参数,工作流在底层会自动生成你所需要的svg图片并合并到雪碧图里。
SVG应用的另一个难点,就是作为背景图响应式渲染,雪碧图的background-position和background-size 的计算,这个其实也是其他图像都会存在的一个难点。
我的导师 wenju 之前发过这个计算公式相关的文章:
百分比值()是背景图相对于背景定位区(background positioning area)的百分比,可以控制在容器元素内仅显示Sprites图的部分内容。比如下图中,Sprites图是由四张图像拼成的,要想在容器内仅显示第一张图像,background-size的值应该多少呢?
我们仅需要Sprites图的1/4显示在容器内,那么Sprites图与容器的比例应该是4:1,计算公式为: background-size : ( Sprites width / image width) (Sprites height / image height)
如何计算background-position
我们已知的信息如下:
容器元素的尺寸: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)如果你每次都手动计算的话会被累死吧?所以这一步我们还是集成到了工作流里,在所有合并雪碧图的地方用这个公式自动计算出位置。
而关于SVG的回退方案,已经是老生常谈
比如
<svg width="200" height="200"> <image xlink:href="svg.svg" src="svg.png" width="200" height="200" /> </svg>svg标签方式,缺点必须指定宽高,没有图片的保持款高比例特性,优点兼容性好,兼容所有主流浏览器
或者
<picture> <source type="image/svg+xml" srcset="svg.svg"> <img src="svg.png" target="_blank">腾讯ISUX