px2viewport.js 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. /* eslint-env node */
  2. const postcss = require("postcss");
  3. // excluding regex trick: http://www.rexegg.com/regex-best-trick.html
  4. // Not anything inside double quotes
  5. // Not anything inside single quotes
  6. // Not anything inside url()
  7. // Any digit followed by px
  8. // !singlequotes|!doublequotes|!url()|pixelunit
  9. const pxRegex = /"[^"]+"|'[^']+'|url\([^\)]+\)|(\d*\.?\d+)px/gi;
  10. const defaults = {
  11. viewportWidth: 750,
  12. viewportUnit: "vmin",
  13. propertyBlacklist: [],
  14. minPixelValue: 2,
  15. enableConvertComment: "on",
  16. disableConvertComment: "off",
  17. mediaQuery: false,
  18. };
  19. module.exports = postcss.plugin(
  20. "postcss-pixel-to-viewport",
  21. function (options) {
  22. const opts = Object.assign({}, defaults, options);
  23. const pxReplace = createPxReplace(
  24. opts.viewportWidth,
  25. opts.minPixelValue,
  26. opts.viewportUnit
  27. );
  28. return function (css) {
  29. css.walkDecls(function (decl, i) {
  30. const next = decl.next();
  31. const commentText = next && next.type == "comment" && next.text;
  32. if (
  33. decl.value.indexOf("px") === -1 ||
  34. commentText === opts.disableConvertComment
  35. ) {
  36. commentText === opts.disableConvertComment && next.remove();
  37. return;
  38. }
  39. if (
  40. commentText === opts.enableConvertComment ||
  41. !blacklistedProperty(opts.propertyBlacklist, decl.prop)
  42. ) {
  43. commentText === opts.enableConvertComment && next.remove();
  44. decl.value = decl.value.replace(pxRegex, pxReplace);
  45. }
  46. });
  47. if (opts.mediaQuery) {
  48. css.walkAtRules("media", function (rule) {
  49. if (rule.params.indexOf("px") === -1) return;
  50. rule.params = rule.params.replace(pxRegex, pxReplace);
  51. });
  52. }
  53. };
  54. }
  55. );
  56. function createPxReplace(viewportSize, minPixelValue, viewportUnit) {
  57. return function (m, $1) {
  58. if (!$1) return m;
  59. const pixels = parseFloat($1);
  60. if (pixels <= minPixelValue) return m;
  61. return (
  62. parseFloat(((pixels / viewportSize) * 100).toFixed(5)) + viewportUnit
  63. );
  64. };
  65. }
  66. function blacklistedProperty(blacklist, property) {
  67. if (typeof property !== "string") return;
  68. return blacklist.some(function (regex) {
  69. if (typeof regex === "string") return property.indexOf(regex) !== -1;
  70. return property.match(regex);
  71. });
  72. }