通常网页的资源来讲,图片数量或者图片体积都会在整个项目中占据极大的比重,相比较代码的处理,图片处理显得特别手段有限,可是利用的好能够将用户体验提高上一个台阶css
根据屏幕像素加载不一样的图片尺寸,优势是自适应选择图片保持高清晰度,减小没必要要的请求渲染时间,缺点是增长代码量和项目体积.vue
这是兼容性最好的方法,略显繁琐node
.bg { background-image: url(demo-320w.jpg); } @media (min-device-pixel-ratio: 2){ .bg { background-image: url(demo-640w.jpg); } }
以逗号分隔的一个或多个字符串列表代表一系列用户代理使用的可能的图像。每个字符串由如下组成:webpack
可选地,再加一个空格以后,附加如下的其一:git
w
' 符号。该整数宽度除以sizes属性给出的资源(source)大小来计算获得有效的像素密度,即换算成和x描述符等价的值。x
' 符号。<img srcset="demo-320w.jpg, demo-480w.jpg 1.5x, demo-640w.jpg 2x" src="demo-default.jpg">
根据不一样的像素密度加载不一样的图片,都不符合的状况下会使用src做为默认图,这是用于像素密度的适配github
表示资源大小的、以逗号隔开的一个或多个字符串。每个资源大小包括:web
<img srcset="demo-320w.jpg, demo-480w.jpg 1.5x, demo-640w.jpg 2x" sizes="(max-width: 640px) 100vw, (max-width: 1080px) 33vw, src="demo-default.jpg">
表示图片在640px及如下100%宽度,超过640px但1080px及如下33%宽度,这是用于屏幕宽度的适配 算法
下面是这两个属性的兼容图api
若是想要更加精确控制的话可使用这两个新标签浏览器
<picture> <source media="(max-width: 640px)" srcset="vertical.jpg"> <source media="(min-width: 641px)" srcset="horizontal.jpg"> <img src="default.jpg"> </picture>
media就至关于上面的sizes,这会从上往下判断直到加载符合的资源.
source还有一个type属性用于加载不一样的图片类型
<picture> <source type="image/svg" srcset="default.svg"> <source type="image/webp" srcset="default.webp"> <img src="default.jpg"> </picture>
下面是兼容性
通常这一步应该是由Ui设计负责输给到开发,也不排除部分UI没有作这一步,咱们本身也能够去作处理.
从图片能够看到根据以前图片算法不一样能够压缩的体积也不同,我随便拿了两张图片测试就达到了10%和67%.
例子 | 格式 | 处理前 | 处理后 | 新旧体积比 |
---|---|---|---|---|
图一 | jpg | 189.3KB | 165KB | 87.1% |
图二 | png | 390KB | 127KB | 32.5% |
未处理图
跟原图相比较,肉眼看不出画质有损害
未处理图
处理图
利用webpack插件对项目图片进行压缩处理,基本配置
import ImageminPlugin from 'imagemin-webpack-plugin' import imageminMozjpeg from 'imagemin-mozjpeg' module.exports = { plugins: [ new ImageminPlugin({ plugins: [ imageminMozjpeg({ quality: 65, progressive: true // 可将图片转成渐进式渲染,用户体验较好,可是渲染耗时更久 }) ] }) ] }
例子 | 格式 | 处理前 | 处理后 | 新旧体积比 |
---|---|---|---|---|
图一 | jpg | 189.3KB | 162KB | 85.5% |
图二 | png | 390KB | 94.2KB | 24.1% |
原图
处理图
原图
处理图94.2KB,比上面压缩工具更优秀,画质依然看不太出区别
WebP最初在2010年发布,目标是减小文件大小,但达到和JPEG格式相同的图片质量,但愿可以减小图片档在网络上的发送时间。2011年11月8日,Google开始让WebP支持无损压缩和透明色(alpha通道)的功能,而在2012年8月16日的参考实作libwebp 0.2.0中正式支持。根据Google较早的测试,WebP的无损压缩比网络上找到的PNG档少了45%的文件大小,即便这些PNG档在使用pngcrush和PNGOUT处理过,WebP仍是能够减小28%的文件大小。
从安卓4.2开始也支持,只要兼容代码写得好也足以让项目体积大大减小,safari暂时还不支持,可是也有手段能够支持.
例子 | 格式 | 处理前 | 处理后 | 新旧体积比 |
---|---|---|---|---|
图一 | jpg | 189.3KB | 116KB | 61.2% |
图二 | png | 390KB | 165KB | 42.3% |
(不知道为何没有办法上传webp,因此就不放对比图了)
CDN除了缓存资源之外,还提供了不少额外处理工具,例如图片转换
这是一种更完善的方案,花钱解决各类处理保存转换的难度和工做量,具体API大同小异.
将多个图片合并成一张大图,能够用一个请求拿到所需的图片,而且合并后的体积比合并前的整体积还小,缺点是只能使用背景而且须要定位位置,也能够经过一些插件自动生成样式.
这种很是智能并且方便,可是不适用长期维护或者改动频繁的项目
Webpack plugin that converts set of images into a spritesheet and SASS/LESS/Stylus mixins, using spritesmith and spritesheet-templates
示例配置
//webpack.config.js var path = require('path'); var SpritesmithPlugin = require('webpack-spritesmith'); module.exports = { // ... module: { rules: [ {test: /\.styl$/, use: [ 'style-loader', 'css-loader', 'stylus-loader' ]}, {test: /\.png$/, use: [ 'file-loader?name=i/[hash].[ext]' ]} ] }, resolve: { modules: ["node_modules", "spritesmith-generated"] }, plugins: [ new SpritesmithPlugin({ src: { cwd: path.resolve(__dirname, 'src/ico'), glob: '*.png' }, target: { image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'), css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl') }, apiOptions: { cssImageRef: "~sprite.png" } }) ] // ... };
在项目开发中直接配置webpack会更加方便,更多配置可查看仓库
用webpack的基本入门库能够简单实现, url-loader 功能相似于 file-loader,可是在文件大小(单位 byte)低于指定的限制时,能够返回一个 DataURL。
module.exports = { module: { rules: [ { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] } ] } }
只适用于小图片的转换,原理就是经过增长代码量来减小资源请求,因此控制转换的体积限制尤其重要,并且自己的问题也很多
与其余图像格式相比,使用 SVG 的优点在于:
<template> <svg :class="svgClass" aria-hidden="true"> <use :xlink:href="iconName"></use> </svg> </template> <script> export default { name: 'svg-icon', props: { iconClass: { type: String, required: true }, className: { type: String } }, computed: { iconName() { return `#icon-${this.iconClass}` }, svgClass() { if (this.className) { return 'svg-icon ' + this.className } else { return 'svg-icon' } } } } </script> <style scoped> .svg-icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style>
import Vue from 'vue' import SvgIcon from '@/components/SvgIcon'// svg组件 // 注册到全局 Vue.component('svg-icon', SvgIcon) const requireAll = requireContext => requireContext.keys().map(requireContext) // eslint-disable-next-line const req = require.context('./svg', false, /\.svg$/) requireAll(req)
import './icons'
<svg-icon icon-class="user" />
Webpack loader for creating SVG sprites.
{ test: /\.svg$/, loader: 'svg-sprite-loader', include: [resolve('src/icons')], options: { symbolId: 'icon-[name]' } } ------------------------------------------- exclude: [resolve('src/icons')],
具体参考张鑫旭博客SVG精简压缩工具svgo简介和初体验
上面说的全部方式终究仍是图片或者会有某些损耗,而字体图标是以字体形式展现图标
应用代码有几种,目前官方推荐方式是
unicode是字体在网页端最原始的应用方式,特色是:
第一步:拷贝项目下面生成的font-face
@font-face {font-family: 'iconfont'; src: url('iconfont.eot'); src: url('iconfont.eot?#iefix') format('embedded-opentype'), url('iconfont.woff') format('woff'), url('iconfont.ttf') format('truetype'), url('iconfont.svg#iconfont') format('svg'); }
第二步:定义使用iconfont的样式
.iconfont{ font-family:"iconfont" !important; font-size:16px;font-style:normal; -webkit-font-smoothing: antialiased; -webkit-text-stroke-width: 0.2px; -moz-osx-font-smoothing: grayscale;}
第三步:挑选相应图标并获取字体编码,应用于页面
<i class="iconfont">3</i>
font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。
与unicode使用方式相比,具备以下特色:
第一步:拷贝项目下面生成的fontclass代码:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.css
第二步:挑选相应图标并获取类名,应用于页面:
<i class="iconfont icon-xxx"></i>
这是一种全新的使用方式,应该说这才是将来的主流,也是平台目前推荐的用法。相关介绍能够参考这篇文章 这种用法实际上是作了一个svg的集合,与上面两种相比具备以下特色:
font-size
,color
来调整样式。第一步:拷贝项目下面生成的symbol代码:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js
第二步:加入通用css代码(引入一次就行):
<style type="text/css"> .icon { width: 1em; height: 1em; vertical-align: -0.15em; fill: currentColor; overflow: hidden; } </style>
第三步:挑选相应图标并获取类名,应用于页面:
<svg class="icon" aria-hidden="true"> <use xlink:href="#icon-xxx"></use> </svg>
这个是比较老生常谈的手段了,从JQ时代开始就已经有比较丰富的经验,到了框架时代,若是用Vue的话我知道的就有
功能比较强大
import Vue from 'vue' import App from './App.vue' import VueLazyload from 'vue-lazyload' Vue.use(VueLazyload) // or with options Vue.use(VueLazyload, { preLoad: 1.3, error: 'dist/error.png', loading: 'dist/loading.gif', attempt: 1 }) new Vue({ el: 'body', components: { App } })
可自定义加载和错误图
<div v-lazy-container="{ selector: 'img', error: 'xxx.jpg', loading: 'xxx.jpg' }"> <img data-src="//domain.com/img1.jpg"> <img data-src="//domain.com/img2.jpg"> <img data-src="//domain.com/img3.jpg"> </div> // 或者 <div v-lazy-container="{ selector: 'img' }"> <img data-src="//domain.com/img1.jpg" data-error="xxx.jpg"> <img data-src="//domain.com/img2.jpg" data-loading="xxx.jpg"> <img data-src="//domain.com/img3.jpg"> </div>
一次性加载完图片再开始渲染界面
<script> export default { data () { return { count: 0, } }, mounted: function() { this.preload() }, methods: { preload: function() { const imgs = ['xxx.png', ...] for (let img of imgs) { const image = new Image() image.src = img image.onload = () => { this.count++ } } }, }, } </script>