diff --git a/LICENSE b/LICENSE index 2c992c2..e0b8d48 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 Dmitry Karpunin +Copyright (c) 2016 Dmitry Karpunin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a9dd07 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# postcss-px-to-viewport [![NPM version](https://badge.fury.io/js/postcss-px-to-viewport.svg)](http://badge.fury.io/js/postcss-px-to-viewport) + +A plugin for [PostCSS](https://github.com/ai/postcss) that generates viewport units (vw, vh, vmin, vmax) from pixel units. + +## Usage + +TODO... diff --git a/example/index.js b/example/index.js new file mode 100755 index 0000000..6d10bde --- /dev/null +++ b/example/index.js @@ -0,0 +1,17 @@ +'use strict'; + +var fs = require('fs'); +var postcss = require('postcss'); +var pxToViewport = require('..'); +var css = fs.readFileSync('main.css', 'utf8'); +var options = { + replace: false +}; +var processedCss = postcss(pxToViewport(options)).process(css).css; + +fs.writeFile('main-viewport.css', processedCss, function (err) { + if (err) { + throw err; + } + console.log('File with viewport units written.'); +}); diff --git a/example/main-viewport.css b/example/main-viewport.css new file mode 100644 index 0000000..5dc5021 --- /dev/null +++ b/example/main-viewport.css @@ -0,0 +1,23 @@ +.class { + margin: -3.125vw .5vh; + padding: 5vmin 2.96875vw; + border: 0.9375vw solid black; + font-size: 4.375vw; + line-height: 6.25vw; +} +.class2 { + font-size: 6.25vw; + line-height: 9.375vw; +} +@media (min-width: 750px) { + .class3 { + font-size: 5vw; + line-height: 6.875vw; + } +} + +/* +.class { + font-size: 16px; +} +*/ diff --git a/example/main.css b/example/main.css new file mode 100755 index 0000000..62039bc --- /dev/null +++ b/example/main.css @@ -0,0 +1,23 @@ +.class { + margin: -10px .5vh; + padding: 5vmin 9.5px; + border: 3px solid black; + font-size: 14px; + line-height: 20px; +} +.class2 { + font-size: 20px; + line-height: 30px; +} +@media (min-width: 750px) { + .class3 { + font-size: 16px; + line-height: 22px; + } +} + +/* +.class { + font-size: 16px; +} +*/ diff --git a/index.js b/index.js new file mode 100755 index 0000000..b29e4c5 --- /dev/null +++ b/index.js @@ -0,0 +1,85 @@ +'use strict'; + +var postcss = require('postcss'); +var objectAssign = require('object-assign'); + +// excluding regex trick: http://www.rexegg.com/regex-best-trick.html +// Not anything inside double quotes +// Not anything inside single quotes +// Not anything inside url() +// Any digit followed by px +// !singlequotes|!doublequotes|!url()|pixelunit +var pxRegex = /"[^"]+"|'[^']+'|url\([^\)]+\)|(\d*\.?\d+)px/ig; + +var defaults = { + viewportWidth: 320, + viewportHeight: 568, + unitPrecision: 5, + viewportUnit: 'vw', + selectorBlackList: [], + //propWhiteList: ['font', 'font-size', 'line-height', 'letter-spacing'], + replace: true, + mediaQuery: false +}; + +module.exports = postcss.plugin('postcss-px-to-viewport', function (options) { + + var opts = objectAssign({}, defaults, options); + var pxReplace = createPxReplace(opts.viewportWidth, opts.unitPrecision, opts.viewportUnit); + + return function (css) { + + css.walkDecls(function (decl, i) { + // This should be the fastest test and will remove most declarations + if (decl.value.indexOf('px') === -1) return; + + // if (opts.propWhiteList.length && opts.propWhiteList.indexOf(decl.prop) === -1) return; + + if (blacklistedSelector(opts.selectorBlackList, decl.parent.selector)) return; + + //var value = decl.value.replace(pxRegex, pxReplace); + // + ////// if viewport unit already exists, do not replace + ////if (declarationExists(decl.parent, decl.prop, value)) return; + // + //decl.value = value; + decl.value = decl.value.replace(pxRegex, pxReplace); + }); + + if (opts.mediaQuery) { + css.walkAtRules('media', function (rule) { + if (rule.params.indexOf('px') === -1) return; + rule.params = rule.params.replace(pxRegex, pxReplace); + }); + } + + }; +}); + +function createPxReplace(viewportSize, unitPrecision, viewportUnit) { + return function (m, $1) { + if (!$1) return m; + var pixels = parseFloat($1); + return toFixed((pixels / viewportSize * 100), unitPrecision) + viewportUnit; + }; +} + +function toFixed(number, precision) { + var multiplier = Math.pow(10, precision + 1), + wholeNumber = Math.floor(number * multiplier); + return Math.round(wholeNumber / 10) * 10 / multiplier; +} + +//function declarationExists(decls, prop, value) { +// return decls.some(function (decl) { +// return (decl.prop === prop && decl.value === value); +// }); +//} + +function blacklistedSelector(blacklist, selector) { + if (typeof selector !== 'string') return; + return blacklist.some(function (regex) { + if (typeof regex === 'string') return selector.indexOf(regex) !== -1; + return selector.match(regex); + }); +} diff --git a/package.json b/package.json new file mode 100755 index 0000000..4a34827 --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "postcss-px-to-viewport", + "description": "A CSS post-processor that converts px to viewport units (vw, vh, vmin, vmax).", + "version": "0.0.1", + "author": "Dmitry Karpunin ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git@github.com:KODerFunk/postcss-px-to-viewport.git" + }, + "bugs": "https://github.com/KODerFunk/postcss-px-to-viewport/issues", + "homepage": "https://github.com/KODerFunk/postcss-px-to-viewport", + "main": "index.js", + "keywords": [ + "css", + "units", + "pixel", + "px", + "viewport", + "vw", + "vh", + "vmin", + "vmax", + "postcss", + "postcss-plugin" + ], + "dependencies": { + "object-assign": "^4.0.1", + "postcss": "^5.0.2" + } +}