├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── gulpfile.js ├── index.js ├── lib └── fastimagesize.js ├── package.json └── test ├── src ├── css │ ├── second │ │ └── second.css │ └── style.css ├── img │ ├── logo.png │ └── wordpress-logo.svg └── slice │ ├── finder │ ├── icon-close.png │ └── icon-close@2x.png │ ├── icon-close.png │ ├── icon-close@2x.png │ ├── icon-search.png │ ├── icon-search@2x.png │ ├── icon-wh.png │ ├── icon-wh@2x.png │ ├── keyframe1@2x.png │ ├── keyframe2@2x.png │ ├── word.png │ └── word@2x.png └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true; 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | tab_width = 4 7 | end_of_line = lf 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.{json,yml}] 12 | indent_style = space 13 | indent_size = 4 14 | 15 | [README.md] 16 | trim_trailing_whitespace = ignore 17 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "xo", 3 | "rules": { 4 | "indent": [ 5 | "error", 6 | "tab" 7 | ], 8 | "one-var": ["error", { uninitialized: "always", initialized: "never" }], 9 | "space-infix-ops": ["error", {"int32Hint": false}] 10 | }, 11 | "env": { 12 | "mocha": true, 13 | "node": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | test/dist/ 4 | *.log 5 | dist/ 6 | .idea 7 | .git 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .editorconfig 3 | .eslintrc 4 | .idea 5 | node_modules/ 6 | npm-debug.log 7 | CHANGELOG.md 8 | test 9 | gulpfile.js 10 | .travis.yml 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "0.12" 5 | - "4" 6 | - "5" 7 | - "6" 8 | - "stable" 9 | before_script: 10 | - npm install -g mocha 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # Change Log 3 | 4 | Change log for postcss-lazyimagecss. 5 | 6 | ## [0.1.3] - 2016-12-21 7 | 8 | - Add support for detecting even dimensions. 9 | 10 | ## [0.1.2] - 2016-11-07 11 | 12 | - Fix log grammar. 13 | 14 | ## [0.1.1] - 2016-11-05 15 | 16 | - Fix image file or a directory path bugs. 17 | 18 | - Add `chalk` package for a better console log. 19 | 20 | ## [0.1.0] - 2016-11-02 21 | 22 | - Fix bug and release to postcss official github page. 23 | 24 | ## [0.0.11] - 2016-10-15 25 | 26 | - Fix bug with multi path in background-image url. 27 | 28 | ## [0.0.10] - 2016-10-10 29 | 30 | - Add support for multi path in background-image url. 31 | 32 | ## [0.0.8] - 2016-10-09 33 | 34 | - Initial release. 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jeff Ma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # postcss-lazyimagecss 2 | 3 | [![Greenkeeper badge](https://badges.greenkeeper.io/Jeff2Ma/postcss-lazyimagecss.svg)](https://greenkeeper.io/) 4 | 5 | 6 | 7 | [![Build Status](https://travis-ci.org/Jeff2Ma/postcss-lazyimagecss.svg?branch=master)](https://travis-ci.org/Jeff2Ma/postcss-lazyimagecss) 8 | [![npm version](https://badge.fury.io/js/postcss-lazyimagecss.svg)](http://badge.fury.io/js/postcss-lazyimagecss) 9 | 10 | A [PostCSS](https://github.com/postcss/postcss) plugin that generates images's CSS `width` & `height` properties from stylesheets automatically. 11 | 12 | Another lazy way to write CSS, feel free to use it :) 13 | 14 | Based on [gulp-lazyimagecss](https://github.com/weixin/gulp-lazyimagecss). Thanks to [hzlzh](https://github.com/hzlzh) and [littledu](https://github.com/littledu). 15 | 16 | ```css 17 | /* Input */ 18 | .icon-close { 19 | background-image: url(../slice/icon-close.png); //icon-close.png - 16x16 20 | } 21 | 22 | .icon-new { 23 | background-image: url(../slice/icon-new@2x.png); //icon-new@2x.png - 16x16 24 | } 25 | 26 | /* Output */ 27 | .icon-close { 28 | background-image: url(../slice/icon-close.png); 29 | width: 16px; 30 | height: 16px; 31 | } 32 | 33 | .icon-new { 34 | background-image: url(../slice/icon-new@2x.png); 35 | width: 8px; 36 | height: 8px; 37 | background-size: 8px 8px; 38 | } 39 | 40 | ``` 41 | 42 | ## Features 43 | 44 | - Support `jpg`/`jpeg`/`png`/`gif`/`bmp`/`svg` file type. 45 | 46 | - Support retina image (file name should like `demo@2x.png`). 47 | 48 | - Both `background-image: url()` and `background: url()` can be detected successfully. 49 | 50 | - CSS property generating will be ignored if any of those `width` / `height` / `background-size` already set. 51 | 52 | 53 | ## Installation 54 | 55 | Install with npm: 56 | 57 | npm install postcss-lazyimagecss --save-dev 58 | 59 | 60 | Or install width [yarn](https://github.com/yarnpkg/yarn): 61 | 62 | yarn add postcss-lazyimagecss --dev 63 | 64 | ## Usage 65 | 66 | ### Work with [Gulp](http://gulpjs.com/) 67 | 68 | Example: 69 | 70 | ```js 71 | var gulp = require('gulp'); 72 | var postcss = require('gulp-postcss'); 73 | var lazyimagecss = require('postcss-lazyimagecss'); 74 | 75 | gulp.task('css', function () { 76 | return gulp.src('./src/css/*.css') 77 | .pipe(another-plugin()) 78 | .pipe(postcss([lazyimagecss({ 79 | imagePath: ['../img','../slice'] 80 | })])) 81 | .pipe(gulp.dest('./dist/css')); 82 | }); 83 | ``` 84 | 85 | ### Work with Gulp & [gulp-sourcemaps](https://www.npmjs.com/package/gulp-sourcemaps) 86 | 87 | Example: 88 | 89 | ```js 90 | var gulp = require('gulp'); 91 | var postcss = require('gulp-postcss'); 92 | var lazyimagecss = require('postcss-lazyimagecss'); 93 | var sourcemaps = require('gulp-sourcemaps'); 94 | 95 | gulp.task('css', function () { 96 | return gulp.src('./src/css/*.css') 97 | .pipe(sourcemaps.init()) 98 | .pipe(another-plugin()) 99 | .pipe(postcss([lazyimagecss({ 100 | imagePath: ['../img','../slice'] 101 | })])) 102 | .pipe(sourcemaps.write(".")) 103 | .pipe(gulp.dest('./dist')); 104 | }); 105 | ``` 106 | 107 | ## Options 108 | - **imagePath** Set image path to be worked (e.g. `['../slice','../img']`) 109 | 110 | - **width** Whether output `width` properties in CSS ( default: `true` ) 111 | 112 | - **height** Whether output `height` properties in CSS ( default: `true` ) 113 | 114 | - **backgroundSize** Whether output `background-size` properties in CSS ( default: `true` ) 115 | 116 | ## Contributing 117 | 118 | [Issues](https://github.com/Jeff2Ma/postcss-lazyimagecss/issues/) and [Pull requests](https://github.com/Jeff2Ma/postcss-lazyimagecss/pulls) are welcome. 119 | 120 | ```shell 121 | $ git clone https://github.com/Jeff2Ma/postcss-lazyimagecss 122 | $ cd postcss-lazyimagecss 123 | $ npm i 124 | $ gulp 125 | ``` 126 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var postcss = require('gulp-postcss'); 3 | var lazyimagecss = require('./index.js'); 4 | var mocha = require('gulp-mocha'); 5 | 6 | var files = ['index.js']; 7 | var watchFiles = ['index.js', 'test/**/*']; 8 | 9 | gulp.task('lint', function () { 10 | var eslint = require('gulp-eslint'); 11 | return gulp.src(files) 12 | .pipe(eslint()) 13 | .pipe(eslint.format()) 14 | .pipe(eslint.failAfterError()); 15 | }); 16 | 17 | gulp.task('test', function () { 18 | return gulp.src('test/*.js', { read: false }) 19 | .pipe(mocha({ timeout: 1000000 })); 20 | }); 21 | 22 | gulp.task('css', function () { 23 | return gulp.src('./test/src/css/**/*.css') 24 | .pipe(postcss([lazyimagecss({ 25 | imagePath: ['../img', '../slice'] 26 | })])) 27 | .pipe(gulp.dest('./test/dist/css')); 28 | }); 29 | 30 | gulp.task('default', ['watch']); 31 | 32 | gulp.task('watch', function () { 33 | gulp.watch(watchFiles, ['css', 'test', 'lint']); 34 | }); 35 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | var dirname = require('path').dirname; 4 | var postcss = require('postcss'); 5 | var chalk = require('chalk'); 6 | var _ = require('lodash'); 7 | var fastImageSize = require('./lib/fastimagesize'); 8 | 9 | /** 10 | * a helper to find the real image absolute path, 11 | * deal with the issue like `../../img.jpg` and so on. 12 | */ 13 | function fixAbsolutePath(dir, relative) { 14 | // find the first time 15 | var absolute = path.resolve(dir, relative); 16 | 17 | // check if is a image file 18 | var reg = /\.(jpg|jpeg|png|gif|svg|bmp)\b/i; 19 | if (!reg.test(absolute)) { 20 | pluginLog('Not a image file: ', absolute); 21 | return; 22 | } 23 | 24 | if (!fs.existsSync(absolute) && (relative.indexOf('../') > -1)) { 25 | relative = relative.replace('../', ''); 26 | // find the second time 27 | absolute = path.resolve(dir, relative); 28 | } 29 | 30 | return absolute; 31 | } 32 | 33 | function pluginLog(str, arg) { 34 | return console.log('[' + chalk.blue('postcss-lazyimagecss') + '] ' + chalk.red(str) + arg); 35 | } 36 | 37 | /** 38 | * main function 39 | */ 40 | module.exports = postcss.plugin('lazyimagecss', function (options) { 41 | return function (css) { 42 | options = options || {}; 43 | 44 | options = _.extend({ 45 | width: true, 46 | height: true, 47 | backgroundSize: true, 48 | imagePath: [] 49 | }, options); 50 | 51 | var imagePath = options.imagePath; 52 | 53 | if (imagePath.length) { 54 | imagePath = '(' + options.imagePath.join('|') + '/)'; 55 | imagePath = imagePath.replace(/\./g, '\\.'); 56 | } else { 57 | imagePath = ''; 58 | } 59 | 60 | var imageRegex = new RegExp('url\\(["\']?(' + imagePath + '[^)]*?)["\']?\\)'); 61 | 62 | css.walkRules(function (rule) { 63 | rule.walkDecls(/^background(-image)?$/, function (decl) { 64 | var rule = decl.parent; 65 | var nodes = rule.nodes; 66 | var value = decl.value; 67 | // var prop = decl.prop; 68 | var CSSWidth = false; 69 | var CSSHeight = false; 70 | var CSSBGSize = false; 71 | 72 | var matchValue = imageRegex.exec(value); 73 | 74 | if (!matchValue || matchValue[1].indexOf('data:') === 0) { 75 | return; 76 | } 77 | 78 | var relativePath = matchValue[1]; 79 | 80 | var inputDir = dirname(decl.source.input.file); 81 | 82 | var absolutePath = fixAbsolutePath(inputDir, relativePath); 83 | 84 | if (absolutePath === undefined) { 85 | return; 86 | } 87 | 88 | nodes.forEach(function (node) { 89 | if (node.prop === 'width') { 90 | CSSWidth = true; 91 | } 92 | if (node.prop === 'height') { 93 | CSSHeight = true; 94 | } 95 | if (node.prop === 'background-size' || node.prop === '-webkit-background-size') { 96 | CSSBGSize = true; 97 | } 98 | }); 99 | 100 | if (value.indexOf('@2x') > -1) { 101 | options.retina = true; 102 | } else { 103 | options.retina = false; 104 | } 105 | 106 | var info = fastImageSize(absolutePath); 107 | 108 | if (info === undefined) { 109 | pluginLog('File does not exist: ', absolutePath); 110 | return; 111 | } 112 | 113 | if (info.type === 'unknown') { 114 | pluginLog('Unknown type: ', absolutePath); 115 | return; 116 | } 117 | 118 | // check if even dimensions 119 | if (value.indexOf('@2x') > -1 && (info.width % 2 !== 0 || info.height % 2 !== 0)) { 120 | pluginLog('Should have even dimensions: ', absolutePath); 121 | return; 122 | } 123 | 124 | var valueWidth, valueHeight; 125 | 126 | if (options.retina) { 127 | valueWidth = (info.width / 2) + 'px'; 128 | valueHeight = (info.height / 2) + 'px'; 129 | } else { 130 | valueWidth = info.width + 'px'; 131 | valueHeight = info.height + 'px'; 132 | } 133 | 134 | if (options.width && !CSSWidth) { 135 | rule.append({prop: 'width', value: valueWidth}); 136 | } 137 | 138 | if (options.height && !CSSHeight) { 139 | rule.append({prop: 'height', value: valueHeight}); 140 | } 141 | 142 | if (options.backgroundSize && options.retina && !CSSBGSize) { 143 | rule.append({prop: 'background-size', value: valueWidth + ' ' + valueHeight}); 144 | } 145 | }); 146 | }); 147 | }; 148 | }); 149 | -------------------------------------------------------------------------------- /lib/fastimagesize.js: -------------------------------------------------------------------------------- 1 | // 2 | // fast-image-size - Simple stand alone module to just extract the image size from image file without using special image libraries. 3 | // 4 | // Please refer to README.md for this module's documentations. 5 | // 6 | // NOTE: 7 | // - Before changing this code please refer to the 'hacking the code section' on README.md. 8 | // 9 | // Copyright (c) 2013 Ziv Barber; 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining 12 | // a copy of this software and associated documentation files (the 13 | // 'Software'), to deal in the Software without restriction, including 14 | // without limitation the rights to use, copy, modify, merge, publish, 15 | // distribute, sublicense, and/or sell copies of the Software, and to 16 | // permit persons to whom the Software is furnished to do so, subject to 17 | // the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be 20 | // included in all copies or substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 26 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 27 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 28 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | // 30 | 31 | var fs = require('fs'); 32 | var path = require('path'); 33 | 34 | module.exports = exports = function (file_path, callback) { 35 | 36 | function getJpgSize(buffer_data, retInfo) { 37 | // Skip 5 chars, they are for signature 38 | buffer_data = buffer_data.slice(4); 39 | 40 | var i, next; 41 | while (buffer_data.length) { 42 | // read length of the next block 43 | i = buffer_data.readUInt16BE(0); 44 | 45 | // 0xFFC0 is baseline(SOF) 46 | // 0xFFC2 is progressive(SOF2) 47 | next = buffer_data[i + 1]; 48 | if (next === 0xC0 || next === 0xC2) { 49 | return { 50 | 'height': buffer_data.readUInt16BE(i + 5), 51 | 'width': buffer_data.readUInt16BE(i + 7) 52 | }; 53 | } 54 | 55 | // move to the next block 56 | buffer_data = buffer_data.slice(i + 2); 57 | } 58 | } 59 | 60 | function parseHeaderData(buffer_data, callback_data) { 61 | var retInfo = {}; 62 | 63 | // Detect GIF: 64 | if (buffer_data[0] == 0x47 && buffer_data[1] == 0x49 && buffer_data[2] == 0x46) { 65 | retInfo.type = 'gif'; 66 | retInfo.width = (buffer_data[7] * 256) + buffer_data[6]; 67 | retInfo.height = (buffer_data[9] * 256) + buffer_data[8]; 68 | 69 | // Detect JPEG: 70 | } else if (buffer_data[0] == 0xFF && buffer_data[1] == 0xD8 && buffer_data[2] == 0xFF && (buffer_data[3] == 0xE0 || buffer_data[3] == 0xE1)) { 71 | retInfo.type = 'jpeg'; 72 | var size = getJpgSize(buffer_data, retInfo); 73 | retInfo.width = size.width; 74 | retInfo.height = size.height; 75 | 76 | // Detect PNG: 77 | } else if (buffer_data[0] == 137 && buffer_data[1] == 80 && buffer_data[2] == 78 && buffer_data[3] == 71 && buffer_data[4] == 13 && buffer_data[5] == 10 && buffer_data[6] == 26 && buffer_data[7] == 10) { 78 | retInfo.type = 'png'; 79 | 80 | if (buffer_data[12] == 0x49 && buffer_data[13] == 0x48 && buffer_data[14] == 0x44 && buffer_data[15] == 0x52) { 81 | retInfo.width = (buffer_data[16] * 256 * 256 * 256) + (buffer_data[17] * 256 * 256) + (buffer_data[18] * 256) + buffer_data[19]; 82 | retInfo.height = (buffer_data[20] * 256 * 256 * 256) + (buffer_data[21] * 256 * 256) + (buffer_data[22] * 256) + buffer_data[23]; 83 | } // Endif. 84 | 85 | // Detect BMP: 86 | } else if (buffer_data[0] == 0x42 && buffer_data[1] == 0x4D) { 87 | retInfo.type = 'bmp'; 88 | retInfo.width = (buffer_data[21] * 256 * 256 * 256) + (buffer_data[20] * 256 * 256) + (buffer_data[19] * 256) + buffer_data[18]; 89 | retInfo.height = (buffer_data[25] * 256 * 256 * 256) + (buffer_data[24] * 256 * 256) + (buffer_data[23] * 256) + buffer_data[22]; 90 | } // Endif. 91 | 92 | retInfo.image = file_path; 93 | if (!retInfo.type) { 94 | retInfo.type = 'unknown'; 95 | } // Endif. 96 | 97 | if (callback_data) { 98 | callback_data(retInfo); 99 | } // Endif. 100 | 101 | return retInfo; 102 | }; 103 | 104 | function getSVGImageSize(data) { 105 | var retInfo = {}; 106 | 107 | retInfo.type = 'svg'; 108 | retInfo.width = data.match(/ -1){ 141 | var fd = fs.openSync(file_path, "r"); 142 | var bufferSize = fs.fstatSync(fd).size; 143 | var buffer = new Buffer(bufferSize); 144 | var bytesRead = fs.readSync(fd, buffer, 0, bufferSize, 0); 145 | fs.closeSync(fd); 146 | return getSVGImageSize(buffer.toString(),null); 147 | }else{ 148 | var fd = fs.openSync(file_path, "r"); 149 | var bufferSize = fs.fstatSync(fd).size; 150 | var buffer = new Buffer(bufferSize); 151 | var bytesRead = fs.readSync(fd, buffer, 0, bufferSize, 0); 152 | fs.closeSync(fd); 153 | return parseHeaderData(buffer, null); 154 | } 155 | 156 | 157 | } // Endif. 158 | }; 159 | 160 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-lazyimagecss", 3 | "version": "0.1.3", 4 | "description": "A PostCSS plugin that generates images's CSS width & height properties from stylesheets automatically.", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "chalk": "^1.1.3", 11 | "lodash": "^4.17.4", 12 | "postcss": "^6.0.0" 13 | }, 14 | "devDependencies": { 15 | "eslint": "^3.7.1", 16 | "eslint-config-xo": "^0.18.1", 17 | "gulp": "^3.9.1", 18 | "gulp-eslint": "^3.0.1", 19 | "gulp-mocha": "^4.1.0", 20 | "gulp-postcss": "^7.0.0", 21 | "mocha": "^3.4.2", 22 | "should": "^11.1.0", 23 | "through2": "^2.0.1", 24 | "vinyl-fs": "^2.4.3" 25 | }, 26 | "scripts": { 27 | "test": "mocha --repotter spec test" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/Jeff2Ma/postcss-lazyimagecss.git" 32 | }, 33 | "keywords": [ 34 | "PostCSS", 35 | "postcss-plugin", 36 | "Image", 37 | "CSS", 38 | "background-image" 39 | ], 40 | "author": "jeff2ma", 41 | "license": "MIT", 42 | "bugs": { 43 | "url": "https://github.com/Jeff2Ma/postcss-lazyimagecss/issues" 44 | }, 45 | "homepage": "https://github.com/Jeff2Ma/postcss-lazyimagecss#readme" 46 | } 47 | -------------------------------------------------------------------------------- /test/src/css/second/second.css: -------------------------------------------------------------------------------- 1 | .seconde-finder-test { 2 | background: url(../../slice/icon-close.png); 3 | width: 100px; 4 | } 5 | 6 | .seconde-finder-test2 { 7 | background: url(../../slice/finder/icon-close.png); 8 | } 9 | -------------------------------------------------------------------------------- /test/src/css/style.css: -------------------------------------------------------------------------------- 1 | /*正常情况(url 无括号)*/ 2 | .icon-wh { 3 | font-size: 23px; 4 | background-image: url(../slice/icon-wh.png); 5 | margin: 0 0 0 5px; 6 | vertical-align: -1px; 7 | display: flex; 8 | } 9 | 10 | /*正常情况 2x */ 11 | .icon-wh2 { 12 | background-image: url(../slice/icon-wh@2x.png); 13 | } 14 | 15 | /*含有其它值的情况*/ 16 | .bg { 17 | width: 100%; 18 | background: url(../slice/icon-close.png) no-repeat center center; 19 | } 20 | 21 | /*无 url 值情况*/ 22 | .background-color { 23 | background: #000; 24 | } 25 | 26 | /* base64 的情况*/ 27 | .base64 { 28 | background-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS41LWMwMTQgNzkuMTUxNDgxLCAyMDEzLzAzLzEzLTEyOjA5OjE1ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MjI2ODJCNzlCQTVCMTFFNDk4RTVBQjQ2RjYyOTA1QzgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MjI2ODJCN0FCQTVCMTFFNDk4RTVBQjQ2RjYyOTA1QzgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyMjY4MkI3N0JBNUIxMUU0OThFNUFCNDZGNjI5MDVDOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoyMjY4MkI3OEJBNUIxMUU0OThFNUFCNDZGNjI5MDVDOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==); 29 | } 30 | 31 | /*远程文件 */ 32 | .remote { 33 | background-image: url(http://devework.com/wp-admin/images/wordpress-logo.svg); 34 | } 35 | 36 | /*svg 文件*/ 37 | .svg-file { 38 | background-image: url(../img/wordpress-logo.svg); 39 | } 40 | 41 | /*代码已经有width heigth 的情况 + url 为双引号的情况*/ 42 | .icon-search { 43 | background-image: url("../slice/icon-search.png"); 44 | width: 1000000px; 45 | height: 33333px; 46 | } 47 | 48 | /*代码已经有background-size + url 为单引号的情况 的情况*/ 49 | .icon-search2 { 50 | background-image: url('../slice/icon-search@2x.png'); 51 | -webkit-background-size: 150px 30px; 52 | background-size: 150px 30px; 53 | } 54 | 55 | /*background 属性的情况*/ 56 | .icon-close { 57 | background: url(../slice/icon-close.png); 58 | } 59 | 60 | /*其它图片文件夹的情况*/ 61 | .logo { 62 | background: url(../img/logo.png); 63 | max-width: 100%; 64 | min-heigth: 200px; 65 | } 66 | 67 | /* media 的情况*/ 68 | @media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) { 69 | .word { 70 | background-image: url(../slice/word.png); 71 | } 72 | 73 | .word-retina { 74 | background-image: url(../slice/word@2x.png); 75 | } 76 | } 77 | 78 | /* keyframes 的情况*/ 79 | @keyframes anim { 80 | 0% { 81 | background-image: url(../slice/keyframe1@2x.png); 82 | } 83 | 100% { 84 | background-image: url(../slice/keyframe2@2x.png); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /test/src/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/img/logo.png -------------------------------------------------------------------------------- /test/src/img/wordpress-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/slice/finder/icon-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/finder/icon-close.png -------------------------------------------------------------------------------- /test/src/slice/finder/icon-close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/finder/icon-close@2x.png -------------------------------------------------------------------------------- /test/src/slice/icon-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/icon-close.png -------------------------------------------------------------------------------- /test/src/slice/icon-close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/icon-close@2x.png -------------------------------------------------------------------------------- /test/src/slice/icon-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/icon-search.png -------------------------------------------------------------------------------- /test/src/slice/icon-search@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/icon-search@2x.png -------------------------------------------------------------------------------- /test/src/slice/icon-wh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/icon-wh.png -------------------------------------------------------------------------------- /test/src/slice/icon-wh@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/icon-wh@2x.png -------------------------------------------------------------------------------- /test/src/slice/keyframe1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/keyframe1@2x.png -------------------------------------------------------------------------------- /test/src/slice/keyframe2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/keyframe2@2x.png -------------------------------------------------------------------------------- /test/src/slice/word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/word.png -------------------------------------------------------------------------------- /test/src/slice/word@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jeff2Ma/postcss-lazyimagecss/8cbfc38ba9a82f183c69f776b9ef0a58440aad52/test/src/slice/word@2x.png -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var should = require('should'); 2 | var vfs = require('vinyl-fs'); 3 | var through2 = require('through2'); 4 | var postcss = require('gulp-postcss'); 5 | var noop = function () {}; 6 | var lazyimagecss = require('../index.js'); 7 | 8 | describe('postcss-lazyimagecss Unit est', function() { 9 | it('Image `width` -> should be able to get `width` properties.', function(done) { 10 | vfs.src('./test/src/css/style.css') 11 | .pipe(postcss([lazyimagecss({ 12 | imagePath: ['../img','../slice'] 13 | })])) 14 | .pipe(through2.obj(function(file, enc, cb){ 15 | content = file.contents.toString(); 16 | content.match(/width/g).length.should.equal(14); 17 | cb(); 18 | })) 19 | .on('data', noop) 20 | .on('end', done); 21 | }); 22 | 23 | it('Image `height` -> should be able to get `height` properties.', function(done) { 24 | vfs.src('./test/src/css/style.css') 25 | .pipe(postcss([lazyimagecss({ 26 | imagePath: ['../img','../slice'] 27 | })])) 28 | .pipe(through2.obj(function(file, enc, cb){ 29 | content = file.contents.toString(); 30 | content.match(/height/g).length.should.equal(12); 31 | cb(); 32 | })) 33 | .on('data', noop) 34 | .on('end', done); 35 | }); 36 | 37 | it('Image `background-size` -> should be able to get `background-size` properties.', function(done) { 38 | vfs.src('./test/src/css/style.css') 39 | .pipe(postcss([lazyimagecss({ 40 | imagePath: ['../img','../slice'] 41 | })])) 42 | .pipe(through2.obj(function(file, enc, cb){ 43 | content = file.contents.toString(); 44 | content.match(/background-size/g).length.should.equal(7); 45 | cb(); 46 | })) 47 | .on('data', noop) 48 | .on('end', done); 49 | }); 50 | 51 | it('`width` value -> should be able to get correct width value.', function(done) { 52 | vfs.src('./test/src/css/style.css') 53 | .pipe(postcss([lazyimagecss({ 54 | imagePath: ['../img','../slice'] 55 | })])) 56 | .pipe(through2.obj(function(file, enc, cb){ 57 | content = file.contents.toString(); 58 | content.indexOf('width: 14px').should.be.above(0); 59 | cb(); 60 | })) 61 | .on('data', noop) 62 | .on('end', done); 63 | }); 64 | 65 | it('`height` value -> should be able to get correct height value.', function(done) { 66 | vfs.src('./test/src/css/style.css') 67 | .pipe(postcss([lazyimagecss({ 68 | imagePath: ['../img','../slice'] 69 | })])) 70 | .pipe(through2.obj(function(file, enc, cb){ 71 | content = file.contents.toString(); 72 | content.indexOf('height: 16px').should.be.above(2); 73 | cb(); 74 | })) 75 | .on('data', noop) 76 | .on('end', done); 77 | }); 78 | 79 | it('`background-size` value -> should be able to get correct height value.', function(done) { 80 | vfs.src('./test/src/css/style.css') 81 | .pipe(postcss([lazyimagecss({ 82 | imagePath: ['../img','../slice'] 83 | })])) 84 | .pipe(through2.obj(function(file, enc, cb){ 85 | content = file.contents.toString(); 86 | content.indexOf('background-size: 14px 14px').should.be.above(0); 87 | cb(); 88 | })) 89 | .on('data', noop) 90 | .on('end', done); 91 | }); 92 | 93 | 94 | it(' Option: imagePath -> should work with another Option of imagePath.', function(done) { 95 | vfs.src('./test/src/css/style.css') 96 | .pipe(postcss([lazyimagecss({ 97 | imagePath: ['../slice'] 98 | })])) 99 | .pipe(through2.obj(function(file, enc, cb){ 100 | content = file.contents.toString(); 101 | content.match(/width/g).length.should.equal(12); 102 | content.match(/height/g).length.should.equal(10); 103 | content.match(/background-size/g).length.should.equal(7); 104 | cb(); 105 | })) 106 | .on('data', noop) 107 | .on('end', done); 108 | }); 109 | 110 | it(' Option: width -> should work when disable Option width.', function(done) { 111 | vfs.src('./test/src/css/style.css') 112 | .pipe(postcss([lazyimagecss({ 113 | imagePath: ['../slice'], 114 | width: false 115 | })])) 116 | .pipe(through2.obj(function(file, enc, cb){ 117 | content = file.contents.toString(); 118 | content.match(/width/g).length.should.equal(4); 119 | cb(); 120 | })) 121 | .on('data', noop) 122 | .on('end', done); 123 | }); 124 | 125 | it(' Option: height -> should work when disable Option height.', function(done) { 126 | vfs.src('./test/src/css/style.css') 127 | .pipe(postcss([lazyimagecss({ 128 | imagePath: ['../slice'], 129 | height: false 130 | })])) 131 | .pipe(through2.obj(function(file, enc, cb){ 132 | content = file.contents.toString(); 133 | content.match(/height/g).length.should.equal(1); 134 | cb(); 135 | })) 136 | .on('data', noop) 137 | .on('end', done); 138 | }); 139 | 140 | it(' Option: backgroundSize -> should work when disable Option backgroundSize.', function(done) { 141 | vfs.src('./test/src/css/style.css') 142 | .pipe(postcss([lazyimagecss({ 143 | imagePath: ['../slice'], 144 | backgroundSize: false 145 | })])) 146 | .pipe(through2.obj(function(file, enc, cb){ 147 | content = file.contents.toString(); 148 | content.match(/background-size/g).length.should.equal(3); 149 | cb(); 150 | })) 151 | .on('data', noop) 152 | .on('end', done); 153 | }); 154 | 155 | it(' Multi path support -> should work in Multi path.', function(done) { 156 | vfs.src('./test/src/css/second/second.css') 157 | .pipe(postcss([lazyimagecss({ 158 | imagePath: ['../../slice'] 159 | })])) 160 | .pipe(through2.obj(function(file, enc, cb){ 161 | content = file.contents.toString(); 162 | content.match(/width/g).length.should.equal(2); 163 | content.match(/height/g).length.should.equal(2); 164 | content.indexOf('width: 100px').should.be.above(0); 165 | cb(); 166 | })) 167 | .on('data', noop) 168 | .on('end', done); 169 | }); 170 | }); 171 | 172 | --------------------------------------------------------------------------------